今天说一下有关动画的基础,希望能帮助到一些刚接触iOS动画或者刚开始学习iOS的同学,如有异议,希望能指正,谢谢。
一、一些基础的概念
下面介绍的都是QuartzCore框架下的内容。
1、CAMediaTimingFunction
时间函数(也被称为缓冲函数),用来描述动画过程中运动的速率情况,也可以看成加速度,apple提供的四种方式:
kCAMediaTimingFunctionLinear 匀速
kCAMediaTimingFunctionEaseIn 慢入
kCAMediaTimingFunctionEaseOut 慢出
kCAMediaTimingFunctionEaseInEaseOut 慢入慢出
kCAMediaTimingFunctionDefault 默认
上面的四种情况可以用下图来表示:
当然,除了给我们提供的方式,我们还可以自定义时间函数,通过+functionWithControlPoints::::方法。
这个方式是传入两个点(control point)(前两个是一个点,后两个是一个点)。第一个点与原点形成第一个切线,第二个点与(1,1)点形成另一个切线,
比如说传入的点为(1,0)和(0.75,1),则它的速率(加速度)对应的图形:
这样就可以自定义你想要的时间函数。
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是干什么,怎么工作的了。下面举一个例子,在例子中进行简单的说明,先看一下效果图:
这个是一个简单的修改layer的的属性形成的动画,layer的很多属性都是支持隐式动画的,你只需要修改他的属性,它就会自动的加入一个动画的效果。上面的效果,代码如下:
很简单的代码,只是再点击button的时候修改layer的position和backgroundColor。这属于上面提到的隐式transaction,如果改成显示动画是这样写的,
可能你会觉得,这样写的结果跟上面的结果一样的,没办法判断到底是不是显示的动画,你可以去掉下面的commit这一行的代码,运行一下,就会发现,并没有执行动画,这就是上面文档中提到的,commit的操作是讲一系列的事务(transactions)提交,等待下个runLoop时渲染。你还可以通过设置CATransaction来修改动画的时间,和之前学习的CAMediaTimingFunction,代码如下:
当然可以使用+(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的属性时,效果如下图:
从结果看出,隐式动画也是给当前的layer加上了动画效果的。
下面再做一个实验,刚在自定义的UIView中重写的actionForLayer:forKey方法中直接返回的nil,然后对自定义view的layer做隐式动画的效果是:
可以从中看出,再自定义view中的actionforlayer方法被调用之后就给layer加入了动画。当你在actionForLayer:forKey:方法中加入判断:
这样修改position的隐式动画就没有了,只有对backgroundColor的动画。同时也印证了上面提到的4个步骤。
今天就先这么多,后面再补充。。。。。。(未完,待续)