最近学习了一下用缓动函数模拟物理动画的效果,可以实现一些比较高级的动画效果,比如弹簧效果等。
1.缓动函数的动画效果是建立在CALayer层级的关键帧动画基础之上。
2.缓动函数是一系列模拟物理效果(如抛物线)方程式的统称,用以计算给定两点之间的插值。
3.两点之间插得值越多,效果越好,但是会耗费更多的性能。
说了这么多,什么是滑动函数呢?如下图,是缓动函数的各种曲线效果图:
大家可以先去github上下载缓动函数第三方 EasingAnimation,链接地址:https://github.com/YouXianMing/EasingAnimation
大家可以在浏览器里面看一下缓动函数的效果,如下图:
将鼠标移到曲线图上,即可看见红色光标相对应的移动轨迹。
好了,缓动函数介绍完了,现在开始进入正题,如何用缓动函数模拟物理动画效果,上代码。
先创建一个项目 ,将我们下载的第三方中如下四个文件拖入工程中,编译无问题。
//创造一个红色的球状视图
UIView *showView = [[UIView alloc ] initWithFrame:CGRectMake(0, 0, 100, 100)];
showView.layer.cornerRadius = 50;
showView.layer.masksToBounds = YES;
showView.contentMode = UIViewContentModeScaleAspectFill;
showView.backgroundColor = [UIColor redColor];
[self.view addSubview:showView];
}
然后创建关键帧动画(对关键帧动画不熟悉的童鞋可以去看我这篇文章 ,关键帧动画很重要,可以让动画按照我们指定的轨迹运行。)http://www.jianshu.com/p/2bdceb8844ed
CAKeyframeAnimation *keyFrameA = [CAKeyframeAnimation animation];
keyFrameA.keyPath = @"position";
keyFrameA.duration = 2.f;
keyFrameA.values = [YXEasing calculateFrameFromPoint:showView.center toPoint:CGPointMake(50, self.view.frame.size.height - 50) func:BounceEaseOut frameCount:30 * 2];//values后面原本跟的是数组,在这里我们调用缓动函数中的calculateFrameFromPoint方法,表示一个起始点到终止点,func代表的参数是缓动函数的效果,framecount则是帧数,一般我们人眼识别的最大帧数是30帧,上面设了2秒,则乘以2
showView.center = CGPointMake(50, self.view.frame.size.height - 50); //设置一下终点位置,让效果到终点位置停下来
[showView.layer addAnimation:keyFrameA forKey:nil];
效果如下,碰撞效果:
再示例一个弹簧效果,比如钟表上秒针的来回抖动
//创建一个表盘
UIView *biaoView = [[UIView alloc ] initWithFrame:CGRectMake(0, 0, 300, 300)];
biaoView.center = self.view.center;
biaoView.layer.borderWidth = 1.f;
biaoView.layer.cornerRadius = 150;
biaoView.layer.borderColor = [UIColor redColor].CGColor;
[self.view addSubview:biaoView];
//创建出layer,也就是秒针
self.secLayer = [CALayer layer]; //secLayer是创建的全局变量
self.secLayer.anchorPoint = CGPointMake(0, 0);//anchorPoint属性是layer的转动点,就好比一个图钉扣在纸上,纸随着图钉而转动,在这里设为最上面的起点 。不理解的话请访问网址:http://www.tuicool.com/articles/MvI7fu3
self.secLayer.frame = CGRectMake(150, 150, 1, 150);
self.secLayer.backgroundColor = [UIColor blueColor].CGColor;
[biaoView.layer addSublayer:self.secLayer];
//创建定时器
self.timer = [NSTimer scheduledTimerWithTimeInterval:1.f target:self selector:@selector(timerEvent) userInfo:nil repeats:YES];
//定义两个宏
//弧度转角度
#define RADIANS_TO_DEGREES(radians) ((radians) * (100.0 / M_PI))
//角度转弧度
#define DEGREES_TO_RADIANS(angle) ((angle) / 100.0 * M_PI)
- (void)timerEvent {
static int i = 1;
//在这里,我们要得到每秒转动的弧度
CGFloat oldValue = DEGREES_TO_RADIANS((360 / 60) * i++);
CGFloat newValue = DEGREES_TO_RADIANS((360 / 60) * i);
CAKeyframeAnimation *keyFrameA = [CAKeyframeAnimation animation];
keyFrameA.keyPath = @"transform.rotation.z";
keyFrameA.duration = 0.5f; //由于表是每秒进行的,所以动画不可能用1秒,在这里我们设置动画效果为0.5秒
keyFrameA.values = [YXEasing calculateFrameFromValue:oldValue toValue:newValue func:ElasticEaseOut frameCount:0.5 * 30];//调用calculateFrameFromValue,表示从老弧度到新弧度,这里的func用的是弹簧效果ElasticEaseOut,帧数设置为30 * 0.5
self.secLayer.transform = CATransform3DMakeRotation(newValue, 0, 0, 1);//绕着z轴转动的newValue,让其每次动画后保持当前位置继续动画
[self.secLayer addAnimation:keyFrameA forKey:nil];
}
效果如下
缓动函数还有很多用法,主要还是看缓动函数的那张图,每种类型有三张方法,比如上面的弹簧效果,如下图:
根据自己需要的效果,然后再easing.h中找到对应的func。
博主也就是起个抛砖引玉的作用,主要还是靠自己去认知,毕竟动画不是死的。