I want to create an animation similar to the animation for changing inbetween different views in the Spy Mouse app. See this video for reference:
http://www.youtube.com/watch?v=ylFdl7W3Srw
I am unable to do the same. My animation shows a rectangular region instead of a circular view.
CABasicAnimation *cornerRadiusAction = [CABasicAnimation animationWithKeyPath:@"cornerRadius"];
cornerRadiusAction.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
cornerRadiusAction.duration = 5.0f;
cornerRadiusAction.toValue = [NSNumber numberWithFloat:self.view.bounds.size.height*2];
[self.view.layer addAnimation:cornerRadiusAction forKey:nil];
You cannot achieve such an effect simply animating the cornerRadius
. You need to use masking of the CALayer
and animate change of the size of a circular mask. Code below does what you want. The animated GIF
shows it in action.
@property (weak, nonatomic) IBOutlet UIView *customView;
- (IBAction)buttonTapped:(id)sender
{
// Set up the shape of the circle.
CGFloat maskDiameter = sqrtf(powf(CGRectGetWidth(_customView.bounds), 2)
+ powf(CGRectGetHeight(_customView.bounds), 2));
CAShapeLayer *mask = [CAShapeLayer layer];
// Make a circular shape.
mask.path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0.0f,
0.0f,
maskDiameter,
maskDiameter)
cornerRadius:maskDiameter/2.0f].CGPath;
// Center the shape in the view.
mask.position = CGPointMake((CGRectGetWidth(_customView.bounds) - maskDiameter)/2,
(CGRectGetHeight(_customView.bounds) - maskDiameter)/2);
// Fill the circle.
mask.fillColor = [UIColor blackColor].CGColor;
// Add as a mask to the parent layer
_customView.layer.mask = mask;
// Animate.
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"path"];
animation.duration = 5.0f;
animation.fillMode = kCAFillModeForwards;
animation.removedOnCompletion = NO;
// Create new path.
CGPathRef newPath = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(maskDiameter/2.0f,
maskDiameter/2.0f,
0.0f,
0.0f)
cornerRadius:0.0f].CGPath;
// Set start and end values.
animation.fromValue = (id)mask.path;
animation.toValue = (__bridge id)newPath;
// Start the animaiton.
[mask addAnimation:animation forKey:@"path"];
}