I want to create an animation with several key frames. I want my Layer (a button in this case) to scale up to 1.5 then down to 0.5 then up to 1.2 then down to 0.8 then 1.0.<
Two alternative solutions for you:
First, You can also animate the transform property.
Using Brad's code, but using @"transform" for the keypath. The primary advantage being that you do not have to calculate the actual frame, but instead provide a simple scaling factor:
Objective-C:
CAKeyframeAnimation *boundsOvershootAnimation = [CAKeyframeAnimation animationWithKeyPath:@"transform"];
CATransform3D startingScale = CATransform3DScale (layer.transform, 0, 0, 0);
CATransform3D overshootScale = CATransform3DScale (layer.transform, 1.2, 1.2, 1.0);
CATransform3D undershootScale = CATransform3DScale (layer.transform, 0.9, 0.9, 1.0);
CATransform3D endingScale = layer.transform;
NSArray *boundsValues = [NSArray arrayWithObjects:[NSValue valueWithCATransform3D:startingScale],
[NSValue valueWithCATransform3D:overshootScale],
[NSValue valueWithCATransform3D:undershootScale],
[NSValue valueWithCATransform3D:endingScale], nil];
[boundsOvershootAnimation setValues:boundsValues];
NSArray *times = [NSArray arrayWithObjects:[NSNumber numberWithFloat:0.0f],
[NSNumber numberWithFloat:0.5f],
[NSNumber numberWithFloat:0.9f],
[NSNumber numberWithFloat:1.0f], nil];
[boundsOvershootAnimation setKeyTimes:times];
NSArray *timingFunctions = [NSArray arrayWithObjects:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut],
[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut],
[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut],
nil];
[boundsOvershootAnimation setTimingFunctions:timingFunctions];
boundsOvershootAnimation.fillMode = kCAFillModeForwards;
boundsOvershootAnimation.removedOnCompletion = NO;
Swift 4:
let boundsOvershootAnimation = CAKeyframeAnimation(keyPath: "transform")
let startingScale = CATransform3DScale(layer.transform, 0, 0, 0)
let overshootScale = CATransform3DScale(layer.transform, 1.2, 1.2, 1.0)
let undershootScale = CATransform3DScale(layer.transform, 0.9, 0.9, 1.0)
let endingScale = layer.transform
boundsOvershootAnimation.values = [startingScale, overshootScale, undershootScale, endingScale]
boundsOvershootAnimation.keyTimes = [0.0, 0.5, 0.9, 1.0].map { NSNumber(value: $0) }
boundsOvershootAnimation.timingFunctions = [
CAMediaTimingFunction(name:kCAMediaTimingFunctionEaseOut),
CAMediaTimingFunction(name:kCAMediaTimingFunctionEaseInEaseOut),
CAMediaTimingFunction(name:kCAMediaTimingFunctionEaseInEaseOut)
]
boundsOvershootAnimation.fillMode = kCAFillModeForwards
boundsOvershootAnimation.isRemovedOnCompletion = false
Second, and likely easier, is using FTUtils, an open source wrapper for core animation. It includes a stock "springy" animation.
You can get it at: http://github.com/neror/ftutils