I am trying to override the drawRect:
method of UIView in my custom view. However, my view has a border radius defined as:
sub = [[[NSBundle mainBundle] loadNibNamed:@"ProfileView" owner:self options:nil] objectAtIndex:0];
[self addSubview:sub];
[sub setUserInteractionEnabled:YES];
[self setUserInteractionEnabled:YES];
CALayer *layer = sub.layer;
layer.masksToBounds = YES;
layer.borderWidth = 5.0;
layer.borderColor = [UIColor whiteColor].CGColor;
layer.cornerRadius = 30.0;
This works perfectly and places a nice border with a border radius around my view (don't mind the diagonal/straight white lines at the back, they have nothing to do with this view):
However, when I try to override the drawRect:
method in my view, I can see a black background not masking to bounds. I don't do anything (currently), here is my code:
-(void)drawRect:(CGRect)rect{
[super drawRect:rect];
}
And here is the result:
I've changed nothing but the draw method. How can I override the draw method while keeping my view obey the corner radius mask? Is this a bug in iOS or am I missing something?
I don't know the full answer, but I do know that UIView's implementation of drawLayer:inContext:
works differently depending on whether you have implemented drawRect:
or not. Perhaps masking/clipping to bounds is one of those things it does differently.
You can try solving your issue a number of ways:
make your background transparent:
layer.backgroundColor = [UIColor clearColor].CGColor;
clip yourself inside your custom drawRect:
:
- (void)drawRect:(CGRect)rect {
[[UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:30.0] addClip];
[image drawInRect:rect]; // or whatever
}
carve out the corners explicitly:
CGContextBeginPath(c);
CGContextAddArc(c, r, r, r, M_PI, 3*M_PI_2, 0);
CGContextAddLineToPoint(c, 0, 0);
CGContextClosePath(c);
CGContextClip(c);
[[UIColor grayColor] setFill];
UIRectFill(rect);
I stole those last 2 suggestions from this great presentation from WWDC 2010: Advanced Performance Optimization on iPhone OS (video listed at this index page -- annoyingly, no direct link).
This is an old question, but I was recently reading a useful blog post titled Abusing UIView. In it the author advises against overriding drawRect
to do things like add a border when there are other ways of doing it. He says,
Overriding drawRect:
causes a performance hit. I haven’t profiled it,
so I don’t know if it’s a signifigant performance under normal
circumstances (it’s probably not), but in most cases, folks who
override drawRect:
can accomplish what they want much easier by
setting properties on a view’s layer property. If you need to draw an
outline around a view, here’s how you would do it:
#import <QuartzCore/QuartzCore.h>
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
self.layer.borderWidth = 2.f;
self.layer.borderColor = [UIColor redColor].CGColor;
}
return self;
I realize this probably doesn't solve the problem of the black background showing through. It is just something else to think about.
Setting
opaque = false // NO for ObjC
on the view solves the problem.
Probably you shouldn't call the
[super drawRect:rect]
inside your drawRect. Apple says that:
If you subclass UIView directly, your implementation of this method
does not need to call super. However, if you are subclassing a
different view class, you should call super at some point in your
implementation.
It seems that calling the super method causes strange behaviour.