I have a UIView
subclass which uses a CAShapeLayer
mask on its CALayer
. The mask uses a distinct shape, with three rounded corners and a cut out rectangle in the remaining corner.
When I resize my UIView
using a standard animation block, the UIView
itself and its CALayer
resize just fine. The mask, however, is applied instantly, which leads to some drawing issues.
I've tried animating the mask's resizing using a CABasicAnimation
but didn't have any luck getting the resizing animated.
Can I somehow achieve an animated resizing effect on the mask? Do I need to get rid of the mask, or will I have to change something about the way I currently draw the mask (using - (void)drawInContext:(CGContextRef)ctx
).
Cheers, Alex
Animate a movie clip on a mask layerSelect the mask layer in the Timeline. To edit the movie clip in place and to display the movie clip's Timeline, double-click the movie clip on the Stage. Apply motion tweening to the movie clip.
A mask is something that hides one part of an object and exposes another part of the object. Creating a mask is simple: Place the object to be masked on one layer, and the object that will act as a mask on the layer just above it.
I found the solution to this problem. Other answers are partially correct and are helpful.
The following points are important to understanding the solution:
In order to solve, we are going to have to tap into Core Animation ourselves, and can't rely on the UIView animation block to do the work for us.
Simply create a CATransaction
with the same duration that you are using with [UIView animateWithDuration:...]
. This will create a separate animation, but if your durations and easing function is the same, it should animate exactly with the other animations in your animation block.
NSTimeInterval duration = 0.5;// match this to the value of the UIView animateWithDuration: call
[CATransaction begin];
[CATransaction setValue:[NSNumber numberWithFloat:duration] forKey:kCATransactionAnimationDuration];
self.myView.layer.mask.position = CGPointMake(newX, 0);
self.myView.layer.mask.bounds = CGRectMake(0, 0, newWidth, newHeight);
[CATransaction commit];
I use a CAShapeLayer
to mask a UIView
by setting self.layer.mask
to that shape layer.
To animate the mask whenever the size of the view changes I overwrote the -setBounds:
to animate the mask layer path if the bounds are changed during an animation.
Here's how I implemented it:
- (void)setBounds:(CGRect)bounds
{
[super setBounds:bounds];
CAPropertyAnimation *boundsAnimation = (CABasicAnimation *)[self.layer animationForKey:@"bounds"];
// update the mask
self.maskLayer.frame = self.layer.bounds;
// if the bounds change happens within an animation, also animate the mask path
if (!boundsAnimation) {
self.maskLayer.path = [self createMaskPath];
} else {
// copying the original animation allows us to keep all animation settings
CABasicAnimation *animation = [boundsAnimation copy];
animation.keyPath = @"path";
CGPathRef newPath = [self createMaskPath];
animation.fromValue = (id)self.maskLayer.path;
animation.toValue = (__bridge id)newPath;
self.maskLayer.path = newPath;
[self.maskLayer addAnimation:animation forKey:@"path"];
}
}
(For the example self.maskLayer
is set to `self.layer.mask)
My -createMaskPath
calculates the CGPathRef that I use to mask the view. I also update the mask path in -layoutSubviews
.
The mask property of CALayer is not animatable which explains your lack of luck in that direction.
Does the drawing of your mask depend on the frame/bounds of the mask? (Can you provide some code?) Does the mask have needsDisplayOnBoundsChange property set?
Cheers, Corin
To animate the bounds change of the mask layer of a UIView: subclass UIView, and animate the mask with a CATransaction - similar to Kekodas answer but more general:
@implementation UIMaskView
- (void) layoutSubviews {
[super layoutSubviews];
CAAnimation* animation = [self.layer animationForKey:@"bounds"];
if (animation) {
[CATransaction begin];
[CATransaction setAnimationDuration:animation.duration];
}
self.layer.mask.bounds = self.layer.bounds;
if (animation) {
[CATransaction commit];
}
}
@end
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With