8

I can create a mask like this:

CALayer *mask = [CALayer layer];
    mask.contents = (id)[[UIImage imageNamed:@"mask.png"] CGImage];
    mask.frame = CGRectMake(0, 0, 10, 10);
    self.content.layer.mask = mask;

And this will correctly reveal the top left 10 pixels of my content (because mask.png is just a black image). However I want to animate the mask to reveal the rest of the content:

 [UIView animateWithDuration:3.0
                     animations:^{
                         mask.frame = self.content.bounds;
                     }
                     completion:^(BOOL finished){

                     }];

The problem is that there's no animation. The entire content gets displayed immediately. Why does this happen, and how can I animate the mask so that the content is revealed from the upper left?

soleil
  • 12,133
  • 33
  • 112
  • 183

1 Answers1

15

The frame is a derived property of various other properties, such as the position, bounds, anchorPoint, and any transform it has applied to it. It's not recommended to animate this property directly, especially when dealing with lower level CoreAnimation layers.

In this case, I would assume you want to animate the bounds. You can use the UIView animation method above, but when dealing with CALayers directly I prefer to use the CoreAnimation methods of animation.

CGRect oldBounds = mask.bounds;
CGRect newBounds = self.content.bounds;

CABasicAnimation* revealAnimation = [CABasicAnimation animationWithKeyPath:@"bounds"];
revealAnimation.fromValue = [NSValue valueWithCGRect:oldBounds];
revealAnimation.toValue = [NSValue valueWithCGRect:newBounds];
revealAnimation.duration = 3.0;

// Update the bounds so the layer doesn't snap back when the animation completes.
mask.bounds = newBounds;

[mask addAnimation:revealAnimation forKey:@"revealAnimation"];
WDUK
  • 18,870
  • 3
  • 64
  • 72
  • This works, partially. I can see the animation now. However it stops about halfway, instead of revealing the entire content view. Do you know why that might be? – soleil Aug 22 '13 at 23:14
  • I'm not sure to be honest; double check the value within the content's bounds are correct. I'll flesh out the answer to be a bit more robust too. – WDUK Aug 22 '13 at 23:37
  • Actually it was because of the anchor point (defaults to 0.5, 0.5 for some reason). This fixes it: mask.anchorPoint = CGPointMake(0, 0); – soleil Aug 22 '13 at 23:41
  • Be aware if you end up rotating the layer, an anchor point like that will make the rotation pivot on the corner, and not in the center as you expect. See https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/CoreAnimation_guide/CoreAnimationBasics/CoreAnimationBasics.html#//apple_ref/doc/uid/TP40004514-CH2-SW3 for more information – WDUK Aug 22 '13 at 23:43