本文将分为四个部分介绍核心动画:
- 第一部分将介绍核心动画的基本概念。
- 第二部分将介绍动画实现原理。
- 第三部分将介绍iOS中核心动画的基本框架。
- 第四部分将介绍iOS中核心动画的技术实现。
第一部分:核心动画的基本概念。
CALayer
CALayer是屏幕上的一个具有可见内容的矩形区域,是UIView内容渲染的实现。它设计出来的的意义就是为了承载内容视图。CALayer 类是整个图层类的基础,它是所有核心动画图层类的父类。每个CAlayer对象是一个具有frame的图层,它们可以通过合并变换矩阵旋转、偏移、拉伸对应的图层内容。
CALayer类是为了承载内容而生,注意它并不直接绘制内容。本质iOS中我们所见的点、线、面都是由Quartz2D绘制而成。一般给CAlayer提供内容有以下三种方式:
1.使用包含图片内容的 CGImageRef 来显式的设置图层的 contents 的属性。
2.一个委托,它提供或者重绘内容。
3.继承 CALayer 类重载显示的函数。
注意:CALayer 的属性 contentsGravity 允许你在图层的边界内容修改图层的 contents 图片的位置或者伸缩值。默认情况下,内容的图像完全填充层的边界,忽视自然的图像宽高比。
注意:
以上三种方式只是通过不同的方法、不同的层次的API给CALayer提供内容视图。
CALayer基本属性:
CALayer封装一系列的基本属性来操作方便定位和操作图层。
图层的 position 属性是一个 CGPoint 的值,它指定图层相当于它父图层的位置,该值基于父图层的坐标系。
图层的 bounds 属性是一个 CGRect 的值,指定图层的大小(bounds.size)和图层的原点(bounds.origin)。当你重写图层的重画方法的时候,bounds 的原点可以作为图形上下文的原点。
图层拥有一个隐式的 frame,它是 position,bounds,anchorPoint 和 transform 属性的一部分。设置新的 frame 将会相应的改变图层的 position 和 bounds 属性,但是 frame本身并没有被保存。但是设置新的 frame 时候,bounds 的原点不受干扰,bounds 的大小变为 frame 的大小,即 bounds.size=frame.size。图层的位置被设置为相对于锚点(anchor point)的适合位置。当你设置 frame 的值的时候,它的计算方式和 position、bounds、和 anchorPoint 的属性相关。
图层的 anchorPoint 属性是一个 CGPoint 值,它指定了一个基于图层 bounds 的符合位置坐标系的位置。锚点(anchor point)指定了 bounds 相对于 position 的值,同时也作为变换时候的支点。锚点使用单元空间坐标系表示,(0.0,0.0)点接近图层的原点,而(1.0,1.0)是原点的对角点。改变图层的父图层的变换属性(如果存在的话)将会影响到 anchorPoint 的方向,具体变化取决于父图层坐标系的 Y 轴。
当你设置图层的 frame 属性的时候,position 会根据锚点(anchorPoint)相应的改变,而当你设置图层的 position 属性的时候,bounds 会根据锚点(anchorPoint)做相应的改变。
CALayer图层变换:CATransform3D
图层一旦创建,你就可以通过矩阵变换来改变一个图层的几何形状。CATransform3D 的数据结构定义一个同质的三维变换(4x4 CGFloat 值的矩阵),用于图层的旋转,缩放,偏移,歪斜和应用的透视。
图层的两个属性指定了变换矩阵:transform 和 sublayerTransform 属性。图层的transform 属性指定的矩阵结合图层的 anchorPoint 属性作用于图层和图层的子图层上面。图层的sublayerTransform 属性指定的矩阵只会影响图层的子图层,而不会对图层本身产生影响。
可以通过以下的任何一个方法改变 CATransform3D 的数据结构:
使用CATransform3D函数
直接修改数据结构的成员
使用键-值编码改变键路径
CALayer 事物
图层的每个改变都是事务的一部分。CATransaction 是核心动画类,它负责成批的把多个图层树的修改作为一个原子更新到渲染树。
隐式事物:
当图层树被没有获得事务的线程修改的时候将会自动创建隐式事务,当线程的运行循环(run-loop)执行下次迭代的时候将会自动提交事务。比喻:
theLayer.opacity=0.0;
theLayer.zPosition=-200;
thelayer.position=CGPointMake(0.0,0.0);
图层的 opacity,zPosition 和 position 数字,依赖隐式事务来确保动画同时一起发生。
显示事物:
在你修改图层树之前,可以通过给 CATransaction 类发送一个 begin 消息来创建一个显式事务,修改完成之后发送 comit 消息。显式事务在同时设置多个图层的属性的时候(例如当布局多个图层的时候),暂时的禁用图层的行为,或者暂时修改动画的时间的时候非常有用。
你可以在修改图层属性值的时候通过设置事务的 kCATransactionDisableActions值为 YES 来暂时禁用图层的行为。在事务范围所作的任何更改也不会因此而发生的动画。下面显示了一个示例,当把 aLayer 从可视化图层树移除的时候禁用淡出动画。
[CATransaction begin];
[CATransaction setValue:(id)kCFBooleanTrue
forKey:kCATransactionDisableActions];
[aLayer removeFromSuperlayer];
[CATransaction commit];
第二部分:核心动画渲染框架
概念里面 NSView 和 UIView 是典型的视图部分,但是在核心动画里面图层是模型部分。图层封装了几何、时间、可视化属性,同时它提供了图层现实的内容,但是实际显示的过程则不是由它来完成。
每个可见的图层树由两个相应的树组成:一个是呈现树,一个是渲染树。
在模型-视图-控制器(model-view-controller)
核心动画类有以下分类:
1. 提供显示内容的图层类。
图层类是核心动画的核心基础,它提供了一套抽象的概念(假如你使用过 NSView或者 UIView 的话,你一定会对它很 熟悉)。 CALayer 是整个图层类的基础,它是所有核心动画图层类的父类。和视图类(NSView 或 UIView)一样,CALayer 有自己的父图层类,同时也拥有自己子图层类的集合,它们构成了一个图层树的层次结构。图层绘制类似视图一样自底向上,并指定其几何形状相对他们 superlayer,创建一个相对的局部坐标系。然而图层类通过合并变换矩阵允许你旋转、偏移、拉伸对应的图层内容。具体内容将会在后面“图层(Layer)的几何和变换”部分介绍。CALayer 从 Application Kit 和 Cocoa Touch 的视图类分离出来,因为没有必要为了显示内容而继承 CALayer 类。
2.动画和计时类。
核心动画的动画类使用基本的动画和关键帧动画把图层的内容和选取的属性动画的显示出来。所有核心动画的动画类都是从 CAAnimation 类继承而来。CAAnimation实现了 CAMediaTiming 协议,提供了动画的持续时间,速度,和重复计数。CAAnimation 也实现了 CAAction 协议。该协议为图层触发一个动画动作提供了提供标准化响应。动画类同时定义了一个使用贝塞尔曲线来描述动画改变的时间函数。例如,一个匀速时间函数(linear timing function)在动画的整个生命周期里面一直保持速度不变,而渐缓时间函数(ease-out timing function)则在动画接近其生命周期的时候减慢速度。
核心动画额外提供了一系列抽象的和细化的动画类,比如:CATransition 提供了一个图层变化的过渡效果,它能影响图层的整个内容。动画进行的时候淡入淡出(fade)、推(push)、显露(reveal)图层的内容。这些过渡效果可以扩展到你自己定制的 Core Image 滤镜。 CAAnimationGroup 允许一系列动画效果组合在一起,并行显示动画。 CAPropertyAnimation 是一个抽象的子类,它支持动画的显示图层的关键路径中指定的属性 CABasicAnimation 简单的为图层的属性提供修改。 CAKeyframeAnimation 支持关键帧动画,你可以指定的图层属性的关键路径动画,包括动画的每个阶段的价值,以及关键帧时间和计时功能的一系列值。在动画运行是,每个值被特定的插入值替代。
3.布局和约束类。
Application Kit 的视图类相对于 superlayer 提供了经典的“struts and springs”定位模型。图层类兼容这个模型,同时 Mac OS X 上面的核心动画提供了一套更加灵活的布局管理机制,它允许开发者自己修改布局管理器。核心动画的 CAConstraint 类是一个布局管理器,它可以指定子图层类限制于你指定的约束集合。每个约束(CAConstraint 类的实例封装)描述层的几何属性(左,右,顶部或底部的边缘或水平或垂直中心)的关系,关系到其同级之一的几何属性层或 superlayer。
4.事务类,在原子更新的时候组合图层类。
图层的动画属性的每一个修改必然是事务的一个部分。CATransaction 是核心动画核心动画编程指南
里面负责协调多个动画原子更新显示操作。事务支持嵌套使用。核心动画支持两种事务:隐式事务和显式事务。在图层的动画属性被一个线程修改,同时该线程下次迭代的时候自动提交该修改的时候隐式事务自动创建。显式事务发生在程序在修改动画属性之前给 CATransaction 发送了一个开始消息,在动画属性修改之后提交该消息。
第三部分将介绍iOS中核心动画的基本框架。
核心动画提供了一套你可以在你应用程序里面使用的动画类的表现:
CABasicAnimation提供了在图层的属性值间简单的插入,更多的是改变属性值形成的动画。
CAKeyframeAnimation 提供支持关键帧动画。你指定动画的一个图层属性的
关键路径,一个表示在动画的每个阶段的价值的数组,还有一个关键帧时间
的数组和时间函数。这里是系统定义的一系列动画。
CATransition提供了一个影响整个图层的内容过渡效果。在动画显示过程中
采用淡出(fade)、推出(push)、显露(reveal)图层的内容。 常用的过渡效
果可以通过提供你自己定制的核心图像滤镜来扩展,过渡动画。
1.核心动画类
核心动画供了一套你可以在你应用程序里面使用的动画类的表现: CABasicAnimation供了在图层的属性值间简单的插入。
CAKeyframeAnimation 供支持关键帧动画。你指定动画的一个图层属性的关键路径,一个表示在动画的每个阶段的价值的数组,还有一个关键帧时间的数组和时间函数。
CATransition供了一个影响整个图层的内容过渡效果。在动画显示过程中采用淡出(fade)、推出(push)、显露(reveal)图层的内容。 常用的过渡效果可以通过供你自己定制的核心图像滤镜来扩展。除了要指定显示的动画类型,你还必须指定动画的间隔、它的速度(它的插值如何分布在整个动画过程)、动画循环时候的循环次数、动画周期完成的时候是否自动的反转、还有动画结束的时候它的可视化状态。动画类和 CAMediaTiming 协议供所有这些功能甚至更多的功能。
2.图层Action行为
图层的行为在以下情况发生的时候被触发:从图层树里面插入或者删除一个图层,图层的属性值被修改了,或者程序显式要求。通常情况下,行为触发器是动画显示的结果所在。。
2.1 行为对象的角色
一个行为对象是一个通过CAAction协议响应行为标识符的对象。行为标识符使用标准圆点分隔的关键路径来命名。图层负责把行为标识符映射到特定的行为对象。当一个特定标识符的行为对象被确定的时候,它会发送一个CAAction协议定义的消息。
CALayer类提供了默认的CAAnimation的行为对象实例,一个兼容类所有动画层属性CAAction协议。表1中CALayer同样定义了以下没有直接对应到属性的行为触发器和他们的行为标识符。
1.一个layer被插入一个可见的layer树,或者layer的hidden属性被设为NO ---- kCAOnOrderIn
2.一个layer被从一个可见的layer树中移除,或者layer的hidden属性被设为YES---kCAOnOrderOut
- 使用replaceSublayer:with:方法将一个可见树中的layer替换---kCATransition
2.2 采用CAAction协议
CAAction协议定义了行为对象如何被调用。实现CAAction协议的类包含一个方法runActionForKey:object:arguments:。
当行为对象收到一个runActionForKey:object:arguments:的消息时,行为标识符、行为发生所在的图层、额外的参数字典会被作为参数传递给方法。
通常行为对象是CAAnimation的子类实例,它实现了CAAction协议。然而你也可以返回任何实现了CAAction协议的类对象。当实例收runActionForKey:object:arguments:的消息时,它需要执行相应的行为。
当CAAnimation实例受到消息runActionForKey:object:arguments:的时候,它把自己添加到图层的动力里面,触发动画的执行(查看代码1)。
代码 1 runActionForKey:object:arguments: 的实现:启动动画
- (void)runActionForKey:(NSString *)key object:(id)anObject arguments:(NSDictionary *)dict { [(CALayer *)anObject addAnimation:self forKey:key]; }