动画
在使用Core Animation开发动画的本质就是将CALayer中的内容转化为位图从而供硬件操作。
通过beginAnimations:context:和commitAnimations创建的动画是显式动画。
通过UIView的animateWithDuration:animations:方法创建的动画隐式是动画。
CALayer本身并不包含在UIKit中,它不能响应事件。由于CALayer在设计之初就考虑它的动画操作功能,CALayer很多属性在修改时都能形成动画效果,这种属性称为“隐式动画属性”。
但是对于UIView的根图层而言属性的修改并不形成动画效果,因为很多情况下根图层更多的充当容器的做用,如果它的属性变动形成动画效果会直接影响子图层。
layer的层次结构Layer Tree,这种层次结构分为以下三种:
-
Model Tree :也就是我们通常所说的layer。
-
Presentation Tree:呈现出来的layer,也就是我们做动画时你看到的那个layer,可以通过layer.presentationLayer获得。
-
Render Tree :私有,无法访问。主要是对Present
当设置removedOnCompletion 属性为NO以及fillMode属性为kCAFillModeForwards时,也并未改变model tree的位置,但是可以使动画结束后,防止presentation tree被移除并回到动画开始的位置。所以并不建议使用removedOnCompletion配合fillMode的方式来实现动画结束时,图层不跳转回原位的实现,我们应该在动画开始或者结束时重新设置它的位置。
//暂停动画 -(void)animationPause{ //获取当前layer的动画媒体时间 CFTimeInterval interval = [_aniLayer convertTime:CACurrentMediaTime() toLayer:nil]; //设置时间偏移量,保证停留在当前位置 _aniLayer.timeOffset = interval; //暂定动画 _aniLayer.speed = 0; } //恢复动画 -(void)animationResume{ //获取暂停的时间 CFTimeInterval beginTime = CACurrentMediaTime() - _aniLayer.timeOffset; //设置偏移量 _aniLayer.timeOffset = 0; //设置开始时间 _aniLayer.beginTime = beginTime; //开始动画 _aniLayer.speed = 1; }
(2)如果没有委托或委托中没有实现-actionForLayer:forKey:方法,图层会检查actions字典,actions字典是属性名称对应行为的映射字典。 //
self.colorLayer.actions = @{@"backgroundColor":transiton};
(3)如果actions字典中没有对应的属性名称,图层就检查style字典
(4)如果style中也没有对应的行为,那么图层将直接调用-defaultActionForKey:方法,
搜索完,-actionForKey:方法要么返回空(不会有动画发生),要么是CAAction协议对应的对象,然后CALayer拿这个结果对先前和当前的值做动画。
[CATransaction setDisableActions:YES];可通过此方法来禁用隐式动画----
[UIView setAnimationsEnabled:NO];
动画执行的时间取决于当前事务的设置CATransaction,动画类型取决于图层行为。CATransaction
的一部分,它可以同时对多个layer
的属性进行修改,然后成批的将将多个图层树包装起来,一次性发送到渲染服务进程。CATransaction
事务对象被分为implicit
和explicit
两种类型,分别对应隐式
和显式
。implicit transaction
会被投递到线程的下一个runloop
完成处理:API
来显式的使用事务类,并且手动提交给渲染服务进程,这种做法被称作推进过渡
。推进过渡
会生成一个默认时长为0.25s
时长的动画效果来完成属性值的修改。CAAction
行为来帮助自己完成属性修改的行为。代理方法actionForLayer:forKey:
允许三种返回的数据格式来完成不同的修改动作:-
空对象
UIView
在响应代理时默认会返回一个NSNull
对象,表示属性修改后,不实现任何的动作,根据修改后的属性值直接更新视图。但UIView
不总是会返回空对象,如果layer
的修改发生在[UIView animatedXXX]
接口的block
中,每一个修改的属性值UIView
都会返回对应的CABasicAnimation
对象来进行动画修改//这是是显示动画 - nil对象 手动创建并添加到视图上的
CALayer
或其子类在属性修改时,没有获取到具体的修改行为。此时被修改的属性会被CATransaction
记录,最终在下一个runloop
的回调中生成动画来响应本次属性修改。由于这个过程非开发者主动完成的,因此这种动画被称作隐式动画
CAAction
的子类 如果返回的是CAAction
对象,会直接开始动画来响应图层属性的修改。一般返回的对象多为CABasicAnimation
类型,对象中包装了动画时长
、动画初始/结束状态
、动画时间曲线
等关键信息。当CAAction
对象被返回时,会立刻执行动作来响应本次属性修改
隐式动画的修改最终由CATransaction
事务完成,它在主线程的runloop
注册了一个监听者,具体回调发生在before waiting
阶段。在回调中会将所有implicit transactions
以动画的形式展示。
在transaction
回调结束时已经将图层树提交给渲染服务进程了,因此之后即便主线程发生卡顿,也不会影响渲染服务进程的工作。而早于transaction
回调发生的卡顿会导致应用不能将图层树及时的提交到渲染服务进程,从而造成了动画开始前的界面停滞现象。
实际在应用使用中,即便是手指不离开屏幕,cell
依旧能够展示各种动画。因此可以推断出transaction
至少还注册了UITracking
这个模式下的runloop
监听处理