缓动函数简介
- 缓动函数的动画效果是建立在CALayer层级的关键帧动画基础之上
- 缓动函数是一系列模拟物理效果(如抛物线)方程式的统称,用以计算给定两点之间的插值
- 两点之间插的值越多,效果越好,但是会耗费更多的性能
- 只有理解了缓动函数的原理才有可能写出自己想要的效果

缓动函数与关键帧动画的联系
- 关键帧动画需要提供很多的帧来完善动画效果
- 关键帧动画的帧可以通过一定的数学计算来提供需要的帧数
- 关键帧动画只需要提供起始点,结束点,就可以通过缓动函数来计算中间“缺失”的帧
- 缓动函数可以指定计算出多少帧
- 帧数越多,动画越流畅,但同时耗费更多的GPU性能。1秒钟60帧最多了,写得再大也是浪费GPU
代码
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
// 添加显示用的view
UIView *showView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
showView.layer.cornerRadius = 50;
showView.layer.masksToBounds = YES;
showView.backgroundColor = [UIColor redColor];
[self.view addSubview:showView];
// // 基本动画类型
// CABasicAnimation *basicAnimation = [CABasicAnimation animation];
// basicAnimation.keyPath = @"position";
// basicAnimation.duration = 4.f;
//
// // fromValue = A | toValue = B
// basicAnimation.fromValue = [NSValue valueWithCGPoint:showView.center];
// basicAnimation.toValue = [NSValue valueWithCGPoint:CGPointMake(200, 200)];
//
// showView.center = CGPointMake(200, 200);
// [showView.layer addAnimation:basicAnimation forKey:nil];
// 关键帧动画类型
CAKeyframeAnimation *keyFrameAnimation = [CAKeyframeAnimation animation];
keyFrameAnimation.keyPath = @"position";
keyFrameAnimation.duration = 4.f;
keyFrameAnimation.values = [YXEasing calculateFrameFromPoint:showView.center
toPoint:CGPointMake(200, 200)
func:BounceEaseInOut
frameCount:30 * 4];
showView.center = CGPointMake(200, 200);
[showView.layer addAnimation:keyFrameAnimation forKey:nil];
}
用缓动函数模拟弹簧效果
- 使用easeOutElastic函数来创建弹簧效果
- 将easeOutElastic创建出来的帧数组添加到关键帧动画中
- 弹簧效果用途

代码
#import "ViewController.h"
#import "YXEasing.h"
@interface ViewController ()
@property (nonatomic, strong) CALayer *secLayer; // 秒针layer
@property (nonatomic, strong) NSTimer *timer; // 定时器
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
// 创建一个表盘
UIView *showView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 300, 300)];
showView.center = self.view.center;
showView.layer.borderWidth = 1.f;
showView.layer.cornerRadius = 150;
showView.layer.borderColor = [UIColor redColor].CGColor;
[self.view addSubview:showView];
// 创建出秒针layer
self.secLayer = [CALayer layer];
self.secLayer.anchorPoint = CGPointMake(0, 0);
self.secLayer.frame = CGRectMake(150, 150, 1, 150);
self.secLayer.backgroundColor = [UIColor blackColor].CGColor;
[showView.layer addSublayer:self.secLayer];
// 创建定时器
self.timer = [NSTimer scheduledTimerWithTimeInterval:1.f
target:self
selector:@selector(timerEvent)
userInfo:nil
repeats:YES];
}
- (void)timerEvent {
static int i = 1;
CGFloat oldValue = DEGREES_TO_RADIANS((360 / 60.f) * i++);
CGFloat newValue = DEGREES_TO_RADIANS((360 / 60.f) * i);
// 创建关键帧动画
CAKeyframeAnimation *keyFrameAnimation = [CAKeyframeAnimation animation];
keyFrameAnimation.keyPath = @"transform.rotation.z";
keyFrameAnimation.duration = 0.5;
keyFrameAnimation.values = [YXEasing calculateFrameFromValue:oldValue
toValue:newValue
func:ElasticEaseOut
frameCount:0.5 * 30];
self.secLayer.transform = CATransform3DMakeRotation(newValue, 0, 0, 1);
[self.secLayer addAnimation:keyFrameAnimation forKey:nil];
}
用缓动函数模拟碰撞效果
- 使用easeOutBounce函数来创建弹簧效果
- 将easeOutBounce创建出来的帧数组添加到关键帧动画中
- 碰撞效果用途
代码
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
// 创建图片view
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 320, 320)];
imageView.image = [UIImage imageNamed:@"pic"];
imageView.contentMode = UIViewContentModeScaleAspectFill;
[self.view addSubview:imageView];
// 创建关键帧动画(移动距离的动画)
CAKeyframeAnimation *keyFrameAnimation = [CAKeyframeAnimation animation];
keyFrameAnimation.keyPath = @"position";
keyFrameAnimation.duration = 2.f;
keyFrameAnimation.values = \
[YXEasing calculateFrameFromPoint:imageView.center
toPoint:CGPointMake(320 / 2.f, 320 / 2.f + 240)
func:BounceEaseOut
frameCount:2 * 30];
// 添加动画
imageView.center = CGPointMake(320 / 2.f, 320 / 2.f + 240);
[imageView.layer addAnimation:keyFrameAnimation forKey:nil];
}
用缓动函数模拟衰减效果
- 使用easeOutCubic函数来创建弹簧效果
- 将easeOutCubic创建出来的帧数组添加到关键帧动画中
- 衰减效果用途
代码
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
// 背景变暗的view
UIView *backView = [[UIView alloc] initWithFrame:self.view.bounds];
backView.backgroundColor = [UIColor blackColor];
backView.alpha = 0;
[UIView animateWithDuration:1.f animations:^{
backView.alpha = 0.3;
}];
[self.view addSubview:backView];
// 创建模拟的菜单
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(320, 0, 320, 568)];
imageView.image = [UIImage imageNamed:@"pic"];
[self.view addSubview:imageView];
// 创建关键帧动画
CAKeyframeAnimation *keyFrameAnimation = [CAKeyframeAnimation animation];
keyFrameAnimation.keyPath = @"position";
keyFrameAnimation.duration = 1.f;
keyFrameAnimation.values = \
[YXEasing calculateFrameFromPoint:imageView.center
toPoint:CGPointMake(self.view.center.x + 100, self.view.center.y)
func:CubicEaseOut
frameCount:1 * 30];
// 加载关键帧动画
imageView.center = CGPointMake(self.view.center.x + 100, self.view.center.y);
[imageView.layer addAnimation:keyFrameAnimation forKey:nil];
}