Animate the mask of a mask of a CALayer

animation, core-animation, ios, objective-c

Solution

Animating the mask of a mask? I'm surprised that even works in the simulator.

Have you tried nesting two layers, with the parent layer with `masksToBounds` on? You can then set an independent mask on both layers, and the outer layer will effectively mask your inner layer with its own mask (due to `masksToBounds`). It probably doesn't matter which layer gets which mask (because you want the intersection of both masks).

With the code you listed in your question, you would just need to add one line, and comment out one line to get the correct functionality:

self.layer.mask = animationMaskLayer;
//    shapeMaskLayer.mask = animationMaskLayer;

Problem

Goal: I am drawing a custom shape that has a gradient. I also want to animate the drawing of this shape by having it draw in from left to right. Problem: The code below works on an iPad simulator, but it doesn't work on my iPad 4 running iOS 7. Does anyone know how to make this work on the device? Is there a different way to achieve this same result? Explanation of my Code: My code works (only on simulator) using 3 CALayers. - `gradientLayer` holds my gradient. - `shapeMaskLayer` holds my custom shape. - `animationMaskLayer` animates it's path to simulate drawing from left to right `animationMaskLayer --masks--> shapeMaskLayer --masks--> gradientLayer` I then animate the frame of `animationMaskLayer` to animate the whole shape. Code: ``` // Animation Mask Rects CGPathRef leftStartingRectPath = CGPathCreateWithRect(CGRectMake(0, 0, 0, self.frame.size.height), 0); CGPathRef fullViewRectPath = CGPathCreateWithRect(CGRectMake(0, 0, self.frame.size.width, self.frame.size.height), 0); // Animation Mask Layer CAShapeLayer *animationMaskLayer = [CAShapeLayer layer]; animationMaskLayer.path = fullViewRectPath; animationMaskLayer.fillColor = UIColor.blackColor.CGColor; // Shape Mask Layer CAShapeLayer *shapeMaskLayer = [CAShapeLayer layer]; shapeMaskLayer.path = CGPathCreateWithEllipseInRect(self.bounds, 0); shapeMaskLayer.fillColor = [UIColor blueColor].CGColor; shapeMaskLayer.mask = animationMaskLayer; // Gradient Layer CAGradientLayer *gradientLayer = [CAGradientLayer layer]; gradientLayer.frame = self.bounds; gradientLayer.colors = self.colors; gradientLayer.mask = shapeMaskLayer; mountainLayer.anchorPoint = pt(0, 0); mountainLayer.position = pt(0, 0); [self.layer addSublayer:gradientLayer]; // Left To Right Animation CABasicAnimation *leftToRightAnimation = [CABasicAnimation animationWithKeyPath:@"path"]; leftToRightAnimation.duration = 0.5; leftToRightAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]; leftToRightAnimation.fromValue = (__bridge id)leftStartingRectPath; leftToRightAnimation.toValue = (__bridge id)fullViewRectPath; leftToRightAnimation.fillMode = kCAFillModeForwards; leftToRightAnimation.removedOnCompletion = NO; [animationMaskLayer addAnimation:leftToRightAnimation forKey:@"animatePath"]; // Memory Management CGPathRelease(leftStartingRectPath); CGPathRelease(fullViewRectPath); ```

Original source