Search code examples
iosobjective-cuiviewcalayerdrawrect

ios Setting the RoundCorner does not work after override drawRect,but normal UIView is ok


I wrote an example about Wave Animation.The animation is ok,but I don't understand why the custom UIView needs to add "self.layer.masksToBounds = YES" to have the round Corner.

  1. This is a custom UIView. I have rewritten its drawRect. If i don't set "masksToBounds" to YES, the round corner disappear.

    - (instancetype)initWithFrame:(CGRect)frame
    {
        self = [super initWithFrame:frame];
        if (self) {
            self.frame = CGRectMake(10, 40, 300, 300);
            self.layer.cornerRadius = 150;
            self.backgroundColor = [UIColor greenColor];
            self.layer.borderColor = [UIColor blueColor].CGColor;
            self.layer.borderWidth = 2;
            //        self.layer.masksToBounds = YES;  //if write this line,the round corner appear
            self.x_move = 0;
            self.y_move = 300;
        }
        return self;
    }
    
    - (void)drawRect:(CGRect)rect {
    
        CGContextRef context = UIGraphicsGetCurrentContext();
        CGMutablePathRef path = CGPathCreateMutable();
    
        CGContextSetLineWidth(context, 1);
        CGContextSetFillColorWithColor(context, [UIColor grayColor].CGColor);
        CGPathMoveToPoint(path, NULL, 0, 0);
    
        for(float i=0; i<=300; i++){
            float x=i;
            float y = 5 * sin( 0.05 * x+ self.x_move) + self.y_move;
            CGPathAddLineToPoint(path, nil, x, y);
        }
    
        CGPathAddLineToPoint(path, nil, 300, 0);
        CGPathAddLineToPoint(path, nil, 0, 0);
        CGContextAddPath(context, path);
        CGContextFillPath(context);
        CGContextDrawPath(context, kCGPathStroke);
        CGPathRelease(path);
    }
    
    - (void)startAnimation {
        if (self.waveTimer == nil) {
            self.waveTimer = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(refresh) userInfo:nil repeats:YES];
        }
    }
    
    - (void)refresh {
        self.x_move += 0.3;
        self.y_move -= 0.2;
        if(self.y_move - 100 < 0.00001){
            [self.waveTimer invalidate];
        }else{
            [self setNeedsDisplay];
        }
    }
    

ViewController:

self.wave = [[waveAnimation alloc] init];
[self.wave startAnimation];
[self.view addSubview:self.wave];
  1. This is a normal UIView. Its "masksToBunds" is NO, but its round corner shows normal. Compared with the examples above, why one should add, one does not need.

    UIView *view = [[UIView alloc] initWithFrame:CGRectMake(20, 60, 100, 100)];
    view.backgroundColor = [UIColor greenColor];
    view.layer.cornerRadius = 50;
    view.layer.borderWidth = 2;
    view.layer.borderColor = [UIColor blackColor].CGColor;
    [self.view addSubview:view];
    

Solution

  • The reason for this is from your override of drawRect:(CGRect)frame.

    You are attempting to set the corner radius of the layer that is not the element you assigned the fill color to. The reason setting masksToBounds achieves the desired rounded corner is because here you are telling the view to mask all of it's layers to the bounds from your frame.

    In your second example with the UIView the corner radius appears as expected because you have not adjusted it's layers.

    I suggest either adopting setting masksToBounds or redraw the view's bounds a different way if you need masksToBounds = NO. Since you have the "squiggle" sin curve and you want rounded corners, perhaps just create a generic rounded rect (one with the desired corner radius) then merge that with the path you have already created with the sin wave.

    Merge multiple CGPaths together to make one path

    That link may help you merge your rounded view with your custom view to achieve the desired end result.

    Otherwise.. probably best bet to just set this to yes.