drawRect is not being called - objective-c

I need to draw an image in a rectangle so for that am using drawRect method.i observed that it is not being called.The output i can see only the blank screen.Am using MAC OS and i need to test the App in Iphone OS 3+.Please can anyone solve my problem.Here is my code:
-(IBAction)calling
{
int a=0;
a=a+1;
[self.view setNeedsDisplay]; //InRect:CGRectMake(78, 43, 200, 138)];
}
- (void)drawRect:(CGRect)rect {
UIImage *myImage = [UIImage imageNamed:#"btbp.jpg"];
CGRect imageRect = CGRectMake(10, 10, 300, 400);
[myImage drawInRect:imageRect];
[self.view setNeedsDisplay];
[myImage release];
}
i donno where i was wrong:(

Is your drawRect method on an actual view? Or is it on the view controller, which is what it seems like? drawRect is something you write/override on the view itself.
You should not call release on the myImage object, since you didn't alloc it yourself.
If this isn't making 100% sense, I'd recommend you start with the iOS Cocoa Views documentation to understand how this all fits together.

Related

drawRect: being called, only shows the frame not the drawing

I have a UIControl subclass where I have drawRect implemented. I am trying to draw a rectangle inside of the drawRect method using a UIBezierPath. All the appropriate methods are being called, nothing is null and the app runs with no issues. The problem is, nothing but the frame is drawn. Meaning, I can see the area of the frame, because it is black, but I cannot see anything that was drawn onto the frame.
Here is what I am doing to instantiate the class:
ZHButton *button =
[[ZHButton alloc] initWithFrame:CGRectMake(100, 200, 100, 50)];
button.buttonType = NSSelectorFromString(LEFT_ROUNDED_CORNER_BUTTON);
[self.view addSubview:button];
Here is the drawRect: method, which calls different methods using a selector:
- (void)drawRect:(CGRect)rect {
UIBezierPath *button = [self performSelector:self.buttonType withObject:nil];
[[UIColor orangeColor] setFill];
[button fill];
}
- (UIBezierPath *)drawButtonWithLeftCornersRounded {
return [UIBezierPath bezierPathWithRoundedRect:self.frame
byRoundingCorners:UIRectCornerTopLeft |
UIRectCornerBottomLeft
cornerRadii:buttonRadii];
}
Everything appears to be working fine, but the UIBezierPath does not get drawn. Also, not sure if using a selector is the best way to do this. Anyone know what is going on with this?
It seems you're not calling the drawButtonWithLeftCornersRounded method. I believe this line is wrong:
[self performSelector:self.buttonType withObject:nil];
But it should be:
[self performSelector:#selector(drawButtonWithLeftCornersRounded) withObject:nil];
Hope this helps!
Solved it. In drawButtonWithLeftCornersRounded bezierPathWithRoundedRect should not be self.frame. This will cause the x and y coordinates to be at the x, y location within the frame, not the view. I changed it the parameter to this:
CGRectMake(0, 0, self.bounds.size.width, self.bounds.size.height);

How to make NSView not clip its bounding area?

I created an empty Cocoa app on Xcode for OS X, and added:
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
self.view = [[NSView alloc] initWithFrame:NSMakeRect(100, 100, 200, 200)];
self.view.wantsLayer = YES;
self.view.layer = [CALayer layer];
self.view.layer.backgroundColor = [[NSColor yellowColor] CGColor];
self.view.layer.anchorPoint = CGPointMake(0.5, 0.5);
self.view.layer.transform = CATransform3DMakeRotation(30 * M_PI / 180, 1, 1, 1);
[self.window.contentView addSubview:self.view];
}
But the rotated layer's background is clipped by the view's bounding area:
I thought since some version of OS X and iOS, the view won't clip the content of its subviews and will show everything inside and outside? On iOS, I do see that behavior, but I wonder why it shows up like that and how to make everything show? (I am already using the most current Xcode 4.4.1 on Mountain Lion).
(note: if you try the code above, you will need to link to Quartz Core, and possibly import the quartz core header, although I wonder why I didn't import the header and it still compiles perfectly)
It turns out that if the line:
((NSView *)self.window.contentView).wantsLayer = YES;
is added to the very beginning, then it works as expected:
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
((NSView *)self.window.contentView).wantsLayer = YES;
self.view = [[NSView alloc] initWithFrame:NSMakeRect(200, 200, 200, 200)];
self.view.wantsLayer = YES;
self.view.layer.backgroundColor = [[NSColor yellowColor] CGColor];
[self.window.contentView addSubview:self.view];
self.view.layer.anchorPoint = CGPointMake(0.5, 0.5);
self.view.layer.transform = CATransform3DMakeRotation(30 * M_PI / 180, 0, 0, 1);
}
So it looks like if all the views are made to be layer backed, then it works the same as it does on iOS. (If there is a quick way to make all views layer backed automatically, that'd be good).
the anchorPoint line cannot be moved before addSubview line, or else it is incorrect, although I wonder why that would make any difference.
The line self.view.layer = [CALayer layer]; can be removed if window.contentView is layer backed. Both the contentView and self.view don't need to set the layer, and I wonder why too.
The transform line cannot be before the addSubview line, or else it won't rotate, and I wonder why too.
The third thing is that, I thought if I go to Interface Builder and make the contentView a class of ContentView (subclassing NSView), and in its init method, do a self.wantsLayer = YES;, then it would work too, but it does not.
But anyway, the code above works, and I will update the reasons above why when I find out more.

How to add an NSView to NSWindow in a Cocoa app?

Since the template of an OS X app in Xcode seems to be similar to an empty app template, the following is used to add a view and a button (trying not to use Interface builder for now):
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
NSView *view = [[NSView alloc] initWithFrame:NSMakeRect(100, 100, 100, 100)];
view.layer.backgroundColor = [[NSColor yellowColor] CGColor];
[self.window.contentView addSubview:view];
NSRect frame = NSMakeRect(10, 40, 90, 40);
NSButton* pushButton = [[NSButton alloc] initWithFrame: frame];
pushButton.bezelStyle = NSRoundedBezelStyle;
[self.window.contentView addSubview:pushButton];
NSLog(#"subviews are %#", [self.window.contentView subviews]);
}
Similar code on iOS should have produced a yellow box and a button, but the code above only produce a button, but the view won't show. Is there something wrong with the code above, and how to make it show the view with a yellow background?
Use setWantsLayer: method of NSView class.
NSView *view = [[NSView alloc] initWithFrame:NSMakeRect(100, 100, 100, 100)];
[view setWantsLayer:YES];
view.layer.backgroundColor = [[NSColor yellowColor] CGColor];
[self.window.contentView addSubview:view];
NSRect frame = NSMakeRect(10, 40, 90, 40);
NSButton* pushButton = [[NSButton alloc] initWithFrame: frame];
pushButton.bezelStyle = NSRoundedBezelStyle;
[self.window.contentView addSubview:pushButton];
NSLog(#"subviews are %#", [self.window.contentView subviews]);
To expand on the suggestion by Kevin Ballard, the classic way to do this is to subclass NSView and override the -drawRect: method. NSRectFill is a very convenient function for filling a rectangle without having to create a bezier path:
- (void)drawRect:(NSRect)rect
{
[[NSColor yellowColor] set];
NSRectFill(rect);
}
NSViews in Cocoa are, by default, not layer-backed. I suspect that if you type
NSLog(#"%#", view.layer);
you will see that it is nil.
In iOS, all views have layers. But on OS X, views don't have layers. In addition, there's 2 "modes" of layer-backed views on OS X. There's what's called a "layer-backed views" and a "layer-hosting view". A layer-backed view uses a CoreAnimation layer to cache drawn data, but you are not allowed to interact with the layer in any way. A layer-hosting view uses a CALayer that you explicitly provide, and you may mess with that layer all you want. However, with a layer-hosting view you may not add any subviews, or use the built-in NSView drawing mechanism. A layer-hosting view must only be used as the root of a CoreAnimation layer hierarchy.
Given all this, you should probably avoid using CoreAnimation at all for your view.
It's possible that an NSBox will do what you want. You can certainly set a fill color there, turn off the border, and set the style to custom. I'm just not 100% certain it will draw as a simple filled rectangle of color. Alternatively you can define your own NSView subclass that draws a color in -drawRect:.

Trying to draw in UIView

Hi I am trying to draw some .png images stored in sandbox and the output the text in UIView. My code is:
-(void)setItemDetails:(ItemShow *)itmShow
{
if(theItem!=itmShow)
{
[theItem release];
theItem=itmShow;
[theItem retain];
}
UIImage *rImage=[UIImage imageNamed:#"years"];
[[UIColor blackColor] set];
[rImage drawInRect:CGRectMake(55.0, 22.0, 17.0, 17.0)];
[[UIColor brownColor] set];
[theItem.itemYear drawAtPoint:CGPointMake(7.0,19.0)
forWidth:100
withFont:[UIFont systemFontOfSize:17.0]
minFontSize:17.0
actualFontSize:NULL
lineBreakMode:UILineBreakModeTailTruncation
baselineAdjustment:UIBaselineAdjustmentAlignBaselines];
}
That after I call this method in viewDidLoad. Nothing happens. I can't see any images and text on canvas of UIView. What's wrong here?
That's right, it is exactly what's supposed to happen (nothing), because viewDidLoad is not the right place from which you do drawing in iOS. You need to implement a different method:
- (void)drawRect:(CGRect)rect {
CGContextRef myContext = UIGraphicsGetCurrentContext();
// Do your drawing in myContext
}
This method of your UIView implementation gets called to do the drawing. Trying to draw on the screen from about anywhere else is not going to produce the desired results.

setNeedsDisplay for UIImage doesn't work

I am trying to draw a line on an UIImage with the help of a dataBuffer when a button gets touched, but the drawRect: .. methode doesn´t get called. (so, the line i want to draw does't appear)
I really don't know where the problem could be, so I posted quite a bit more code. Sorry about that.
By the way, I am working on an viewbasedapplication.
here is my code :
-(void) viewDidLoad{
UIImage *image = [UIImage imageNamed:#"playView2.jpg"];
[playView setImage:image];
[image retain];
offScreenBuffer = [self setupBuffer];
}
- (IBAction)buttonTouched:(id)sender {
[self drawToBuffer];
[playView setNeedsDisplay];
}
- (void)drawRect:(CGRect)rect{
CGImageRef cgImage = CGBitmapContextCreateImage(offScreenBuffer);
UIImage *uiImage = [[UIImage alloc] initWithCGImage:cgImage];
CGImageRelease(cgImage);
[uiImage drawInRect: playView.bounds];
[uiImage release];
}
-(void)drawToBuffer {
// Red Gr Blu Alpha
CGFloat color[4] = {1.0, 1.0, 0.0, 1.0};
CGContextSetRGBStrokeColor(offScreenBuffer, color[0], color[1], color[2], color[3]);
CGContextBeginPath(offScreenBuffer);
CGContextSetLineWidth(offScreenBuffer, 10.0);
CGContextSetLineCap(offScreenBuffer, kCGLineCapRound);
CGContextMoveToPoint(offScreenBuffer, 30,40);
CGContextAddLineToPoint(offScreenBuffer, 150,150);
CGContextDrawPath(offScreenBuffer, kCGPathStroke);
}
-(CGContextRef)setupBuffer{
CGSize size = playView.bounds.size;
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = CGBitmapContextCreate(NULL, size.width, size.height, 8, size.width*4, colorSpace, kCGImageAlphaPremultipliedLast);
CGColorSpaceRelease(colorSpace);
return context;
}
Where is this code? viewDidLoad is a view controller method, drawRect is a view method. Whatever playView is (presumably a UIImageView?) needs to be a custom UIView subclass with your drawRect inside it, and you'll have to pass the various items to that from your view controller.
I know this is an old question but still, someone might come across here:
the same (or very similiar) question is correctly answered here:
drawRect not being called in my subclass of UIImageView
UIImageView class (and it's sublasses) don't call drawRect if you call their setNeedsDisplay.