问题
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?
回答1:
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).
回答2:
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 overridedrawRect: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.
回答3:
Setting
opaque = false // NO for ObjC
on the view solves the problem.
回答4:
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.
来源:https://stackoverflow.com/questions/13746795/uiview-overriding-drawrect-causes-view-not-to-obey-maskstobounds