Use Bezier Path as Clipping Mask

I am wondering if it is possible to clip a view to a Bezier Path. What I mean is that I want to be able to see the view only in the region within the closed Bezier Path. The reason for this is that I have the outline of an irregular shape, and I want to fill in the shape gradually with a solid color from top to bottom. If I could make it so that a certain view is only visible within the path then I could simply create a UIView of the color I want and then change the y coordinate of its frame as I please, effectively filling in the shape. If anyone has any better ideas for how to implement this that would be greatly appreciated. For the record the filling of the shape will match the y value of the users finger, so it can’t be a continuous animation. Thanks.

Update (a very long time later):

  • ios - how to do a native “Pulse effect” animation on a UIButton
  • How to change the Push and Pop animations in a navigation based app
  • UIView surface custom transformation/animation (like 'a water drop effect')
  • Unwind with more than 1 segue using iOS 7 UIViewController transition animations
  • UITextField text jumps when animating width constraint
  • iOS - 2d image turn into a 3d
  • I tried your answer, Rob, and it works great except for one thing. My intention was to move the view being masked while the mask remains in the same place on screen. This is so that I can give the impression of the mask being “filled up” by the view. The problem is that with the code I have written based on your answer, when I move the view the mask moves with it. I understand that that is to be expected because all I did was add it as the mask of the view so it stands to reason that it will move if the thing it’s tied to moves. I tried adding the mask as a sublayer of the superview so that it stays put, but that had very weird results. Here is my code:

    self.test = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 200, 200)];
    self.test.backgroundColor = [UIColor greenColor];
    
    [self.view addSubview:self.test];
    
    UIBezierPath *myClippingPath = [UIBezierPath bezierPath];
    [myClippingPath moveToPoint:CGPointMake(100, 100)];
    [myClippingPath addCurveToPoint:CGPointMake(200, 200) controlPoint1:CGPointMake(self.screenWidth, 0) controlPoint2:CGPointMake(self.screenWidth, 50)];
    [myClippingPath closePath];
    
    
    CAShapeLayer *mask = [CAShapeLayer layer];
    mask.path = myClippingPath.CGPath;
    
    self.test.layer.mask = mask;
    
    CGRect firstFrame = self.test.frame;
    firstFrame.origin.x += 100;
    [UIView animateWithDuration:3 animations:^{
        self.test.frame = firstFrame;
    }];
    

    Thanks for the help already.

    2 Solutions Collect From Internet About “Use Bezier Path as Clipping Mask”

    You can do this easily by setting your view’s layer mask to a CAShapeLayer.

    UIBezierPath *myClippingPath = ...
    
    CAShapeLayer *mask = [CAShapeLayer layer];
    mask.path = myClippingPath.CGPath;
    
    myView.layer.mask = mask;
    

    You will need to add the QuartzCore framework to your target if you haven’t already.


    In Swift …

    let yourCarefullyDrawnPath = UIBezierPath( .. blah blah
    let maskForYourPath = CAShapeLayer()
    maskForYourPath.path = carefullyRoundedBox.CGPath
    layer.mask = maskForYourPath
    

    Just an example of Rob’s solution, there’s a UIWebView sitting as a subview of a UIView called smoothView. smoothView uses bezierPathWithRoundedRect to make a rounded gray background (notice on right). that works fine.

    but if smoothView has only normal clip-subviews, you get this..

    enter image description here

    if you do what Rob says, you get the rounded corners in smoothView and all subviews

    enter image description here

    Great stuff.