iOS 动画基础
原文:http://www.cnblogs.com/lujianwenance/p/5733846.html
今天说一下有关动画的基础,希望能帮助到一些刚接触iOS动画或者刚开始学习iOS的同学,如有异议,希望能指正,谢谢。
一、一些基础的概念
下面介绍的都是QuartzCore框架下的内容。
1、CAMediaTimingFunction
时间函数(也被称为缓冲函数),用来描述动画过程中运动的速率情况,也可以看成加速度,apple提供的四种方式:
kCAMediaTimingFunctionLinear 匀速
kCAMediaTimingFunctionEaseIn 慢入
kCAMediaTimingFunctionEaseOut 慢出
kCAMediaTimingFunctionEaseInEaseOut 慢入慢出
kCAMediaTimingFunctionDefault 默认
上面的四种情况可以用下图来表示:
![](https://images2015.cnblogs.com/blog/744505/201608/744505-20160803174320028-1020507601.jpg)
当然,除了给我们提供的方式,我们还可以自定义时间函数,通过+functionWithControlPoints::::方法。
这个方式是传入两个点(control point)(前两个是一个点,后两个是一个点)。第一个点与原点形成第一个切线,第二个点与(1,1)点形成另一个切线,
![](https://images2015.cnblogs.com/blog/744505/201608/744505-20160803174408934-774557763.jpg)
比如说传入的点为(1,0)和(0.75,1),则它的速率(加速度)对应的图形:
![](https://images2015.cnblogs.com/blog/744505/201608/744505-20160803174426043-1037363012.png)
这样就可以自定义你想要的时间函数。
2、CAMediaTiming
这是一个protocol,被CALayer和CAAnimation遵守,它是一个分级定时系统,描述一个对象相对于父对象到当地时间的映射(有点绕,这句应该怎么翻译,请大神指教:The
CAMediaTiming
protocol models a hierarchical timing system, with each object describing the mapping of time values from the object's parent to local time.)。主要是用来描述动画中的开始、执行时间,执行速率,重复次数等。 3、CFTimeInterval
表示时间间隔,就是double类型,起的别名
4、CATransaction
文档中这样描述的:“Transactions是CoreAnimation批量处理layer-tree去原子的更新渲染的机制,每一个layer tree 的改变都需要transaction这一个部分。CoreAnimation支持两种transactions,“显示”transaction和“隐式”transaction。”显示的transaction是在改变layer tree之前调用[CATransaction begin],然后[CATransaction commit]。隐式的transaction是当没有活跃的transaction的layer tree 在一个线程中被修改时,CoreAnimation自动的创建的transaction,这些transactions在runLoop的下一次迭代中被自动commit,在一些特殊的情况下(比如说没有runLoop或者runLoop被阻塞了),就必须用显示的transaction在合适的时机去渲染layer tree的跟新。”,我相信文档中的描述已经很清晰的说明了CATransaction是干什么,怎么工作的了。下面举一个例子,在例子中进行简单的说明,先看一下效果图:
![](https://images2015.cnblogs.com/blog/744505/201608/744505-20160803174444622-1321128037.gif)
这个是一个简单的修改layer的的属性形成的动画,layer的很多属性都是支持隐式动画的,你只需要修改他的属性,它就会自动的加入一个动画的效果。上面的效果,代码如下:
![](https://images2015.cnblogs.com/blog/744505/201608/744505-20160803174458872-1209506629.png)
很简单的代码,只是再点击button的时候修改layer的position和backgroundColor。这属于上面提到的隐式transaction,如果改成显示动画是这样写的,
![](https://images2015.cnblogs.com/blog/744505/201608/744505-20160803174511622-511601680.png)
可能你会觉得,这样写的结果跟上面的结果一样的,没办法判断到底是不是显示的动画,你可以去掉下面的commit这一行的代码,运行一下,就会发现,并没有执行动画,这就是上面文档中提到的,commit的操作是讲一系列的事务(transactions)提交,等待下个runLoop时渲染。你还可以通过设置CATransaction来修改动画的时间,和之前学习的CAMediaTimingFunction,代码如下:
![](https://images2015.cnblogs.com/blog/744505/201608/744505-20160803174527356-563092201.png)
当然可以使用+(void)setAnimationDuration:(CFTimeInterval)dur;方法来设置动画时间,时间函数也可以。
还有一个关闭隐式动画的方式就是disableAction设置为NO,通过setDisableActions:或者kCATransactionDisableActions都可以。
CATransaction中还提供有setCompletionBlock或者kCATransactionCompletionBlock,使用上面两种方法可以设置动画之后的的回调,这个应该还是很好用的,很多动画之后是需要进行某一个action的。
5、CAAction
这是一个protocol,定义在CALayer的头文件中,CAAnimation和CALayer类遵守了这个协议。它有一个方法,是当一个对象发生一个事件,会调用这个方法,参数为这个事件的name,发生事件的对象anObject,保存这个事件相关的参数dic。
大家都知道UIView是对CALayer的一层封装,UIView遵守了CALayerDelegate,实现就了协议的方法(具体UIView和CALayer的关系和区别这里就不过多的描述了),到这里就会有一个疑问,为什么CALayer的属性有隐式动画,而UIView的layer没有呢?
我们先从CALayer的方法actionForKey:方法说起,当我们改变CALayer的属性时,会调用这个方法传递属性名称:
1、判断当前delegate对象是否实现了actionForLayer:forKey:方法,如果实现就调用;
2、检查这个layer的actions字典中是否有当前属性名称
3、在“style”层面检查任何actions字典中是否有当前属性名称
4、如果上面所有步骤都没有找到,那么就调用默认的defaultActionForKey:方法
注:以上任何一步返回非nil action对象都会被忽略(不做任何操作)
所以,我们可以自定义一个UIView,然后重写父类的actionForLayer:forKey:方法,返回nil,就可以让一个UIView也有隐式动画了,赶紧试试吧。
那隐式动画到底是怎样实现的呢?下面我们继续看看CALayer做了什么,我们给自定义的UIView自定义一个Layer,layer中有添加和移除animation的方法,我们在自定义的CALayer重写addAnimation:forKey:方法,当点击button,改变layer的属性时,效果如下图:
![](https://images2015.cnblogs.com/blog/744505/201608/744505-20160803174545153-1555515016.png)
![](https://images2015.cnblogs.com/blog/744505/201608/744505-20160803174552231-1889758809.png)
从结果看出,隐式动画也是给当前的layer加上了动画效果的。
下面再做一个实验,刚在自定义的UIView中重写的actionForLayer:forKey方法中直接返回的nil,然后对自定义view的layer做隐式动画的效果是:
![](https://images2015.cnblogs.com/blog/744505/201608/744505-20160803174610715-781960003.png)
![](https://images2015.cnblogs.com/blog/744505/201608/744505-20160803174620200-1093932673.png)
可以从中看出,再自定义view中的actionforlayer方法被调用之后就给layer加入了动画。当你在actionForLayer:forKey:方法中加入判断:
![](https://images2015.cnblogs.com/blog/744505/201608/744505-20160803174641340-969523335.png)
这样修改position的隐式动画就没有了,只有对backgroundColor的动画。同时也印证了上面提到的4个步骤。
6、CAAnimation
CAAnimation是一个动画的基础类,与他相关的还有CAPropertyAnimation、CAKeyframeAnimation、CABasicAnimation、CASpringAnimation、CATransition和CAAnimationGroup。他们的结构如下图:
![](https://images2015.cnblogs.com/blog/744505/201608/744505-20160808173841668-75106313.png)
先说CAPropertyAnimation,他是基于property的,他的keyPath就是描述需要动画的属性。additive这个属性是,当被设置为true时说明这个值会被追加的当前layer的这个property的value上,产生一个新的value,当然如果为NO,就相当于给property一个新值。cumulative这个属性,从文档中可以看出有重复次数时才有用,这个属性设为true时这个动画的当前value就是上次动画的结尾的value加上当前重复中的value,如果为false,value就一直是这个值。valueFunction这个是用来转化你设置的动画值为动画需要的矩阵值,不赋值他就有默认的转化方式。
CABasicAnimation,为一个layer的属性提供基本的单个关键帧动画的能力,使用animationWithKeyPath:来初始化,他的三个属性,fromValue、byValue、toValue,至少有一个值不为nil。
CAKeyframeAnimation,关键帧动画,values path keyTimes timintFunctions 这些属性就不多说了,下面主要提一下其他的,calculationMode,计算模式,图形学中的差值计算,这里api中提供了几种模式:
kCAAnimationLinear 默认值,会根据给定的values中的每一个关键帧值之间直线相连进行差值计算
kCAAnimationDiscrete 不进行差值计算,离散的,只是将value中的关键帧一次展示(可以理解成没有过度的动画)
kCAAnimationPaced keyTimes和timingFunctions设置无效,动画匀速执行,平均分配时间
kCAAnimationCubic
kCAAnimationCubicPaced 在cubic的基础上匀速动画
下面专门说一下kCAAnimationCubic,calculationMode的默认值是每个关键帧之间的直线相连进行插值计算,kCAAnimationCubic是圆滑曲线相连进行差值计算,具体曲线的样子由tensionValues、continuityValues和biasValues三个数组的value来计算,如下图:
![](https://images2015.cnblogs.com/blog/744505/201608/744505-20160809163739668-1771733014.png)
t 切线向量的长度 张力值
b 切线向量的方向 斜率
c 切线之间变化的锐度 连续性
想了解详细的数学公式请查看:https://en.wikipedia.org/wiki/Kochanek–Bartels_spline
rotationMode属性是控制匹配路径的切线,默认为nil,还可以设置kCAAnimationRotateAuto和kCAAnimationRotateAutoReverse。
CASpringAnimation,iOS9加入的新的弹簧模型动画类,简单的介绍一下它的属性,mass对象的质量,质量越大压缩和拉伸的幅度越大,默认值1;stiffness弹簧的刚性,刚性越大产生的动力越大,默认值100;damping阻尼系数,系数越大阻力越大,默认值10;initialVelocity初始速率,默认值0,为正和运动方向一致,为负和运动方向相反;settlingDuration结算时间,返回弹簧动画停止的估算时间,通常用来设置动画的执行时长。