Core Animation编程指南
关于Core Animation
Core Animation是iOS与OS X平台上负责图形渲染与动画的基础设施。Core Animation可以动画视图和其他的可视元素。Core Animation为你完成了实现动画所需的大部分绘帧工作。你只需在配置少量的动画参数(如开始点位置和结束点位置)就可启动Core Animation。Core Animation将大部分实际的绘图任务交给了图形硬件处理,图形硬件会加速图形渲染的速度。这种自动化的图形加速让动画具有更高的帧率且更加平滑,但 这并不会增加CPU的负担而导致影响你应用的运行速度。
如果你正在开发一个iOS应用,你就已经使用到了Core Animation;如果你开发的是OS X应用,你仅需小小的付出就可以利用Core Animation的强大功能。如下图,Core Animation位于AppKit和UIKit的底层。它被紧密的集成到了Cocoa和Cocoa Touch视图工作流中。虽然被紧密的集成,Core Animation也存在扩展功能的接口,这些接口暴露给了应用的视图。使用这些接口能让你更细粒度地控制应用中的动画。
![](http://www.cocoachina.com/cms/uploads/allimg/131230/4196_131230103717_1.png)
简介
你可能从不需要直接使用Core Animation,但是当你使用Core Animation,你应该了解Core Animation是你app基础设施中的一部分。
Core Animation管理着你的应用内容
Core Animation自身并不是一个绘图系统。它 只是一个负责在硬件上合成和操纵应用内容的基础构件。Core Animation的核心是图层对象,图层对象用于管理和操控你的应用内容。图层将捕获的内容放到一副位图中,图形硬件能够非常容易的操控你的位图。在大 部分应用中,图层被作为一种管理视图内容的方式,但是你也可以创建标准的图层,这取决于你自身的需要。
更改图层属性会产生动画
你使用Core Animation创建的大部分动画都包含对图层属性的更改。像视图一样,图层对象也具有边框矩形、坐标原点、尺寸、不透明度、变换矩阵以及许多其他面向 可视的属性(如backgroundColor)。大部分这些属性的值发生了变化都将会触发隐式动画被创建。隐式动画是一种从旧属性值动画到新属性值的动 画形式。如果需要全面掌控动画行为,你可以考虑使用显式动画这些属性。
有组织的图层层级
有组织的图层之间存在着父子关系。图层的组织会影响到图层的可见内容。可见内容的管理与视图的管理方法相似。附到视图上的图层集合的层级镜像对应的视图层级。你可以将独立图层添加到图层的层级以扩充你的视图的可视内容。
使用动作对象改变图层的默认行为
通过动作对象可以做到隐式的图层动画。动作对象是 实现了一个预定义接口的常规对象。Core Animation使用动作对象实现与图层关联的常规的默认动画集合。你可以创建属于你自己的动作对象,以实现自定义的动画或者实现其他行为类型,然后你 将动作对象赋值给图层的某一属性。当属性发生变化,Core Animation检索你的动作对象并告诉动作对象执行对应的动作。
如何使用该文档
该文档为那些需要更全面的控制动画效果或打算利用图层提升绘图性能的开发者。该文档也介绍了iOS和OS X对图层和视图的合成。图层和视图的合成在iOS和OS X平台上是不同的,理解这些不同对于创建高效的动画至关重要。
预备知识
你应该了解你的目标平台的视图架构,以及熟悉如何创建基于视图的动画。如果你还未到该阶段,请阅读以下两篇文档:
对于iOS应用开发,你应该理解《iOS视图编程指南》中关于视图架构的描述。
对于OS X应用开发,你应该理解《视图编程指南》中关于视图架构的描述。
Core Animation基础
Core Animation为动画视图和其他可视元素提供了一个通用的系统。Core Animation并不是视图的替代品,相反,它是一种和视图相集成的技术。由于位图可以直接由图形硬件直接操控,通过将视图的内容缓存到位图中, 该技术可获得更优的性能且支持动画视图内容。除了缓存视图内容,Core Animation也定义了指定任意可视内容,然后将内容和视图集成,最后动画视图和其他可视元素的方式。
使用Core Animation让视图和可视对象的变化能以动画的形式呈现。大部分变化都与可视对象属性的更改相关。比如Core Animation能让视图的位置、尺寸或者透明度的变化以动画的形式呈现。当你更改了这些属性的值, Core Animation在当前属性值和最新指定的属性值之间进行动画。你一般不需要像卡通片那样,完成每秒60次的视图内容替换。相反,你应该利用Core Animation提供的移动视图、淡入淡出视图、对视图应用任意的变换、改变视图的其他可视属性的方式完成动画 。
图层是绘图与动画的基础
图层对象是组织在三维空间的二维平面。它是使用Core Animation执行任何操作的核心构件。和视图一样,图层的可管理信息包括几何结构、内容、可视属性;不同于视图,图层没有定义它自己的外观,图层仅管理周围位图的状态信息。位图可以是视图的绘图结果或者一张图片。因此主要的图层被认为是模型对象,因为它们主要是用于管理数据。此概念务必记住,因为它影响到动画的行为。
基于图层的绘图模型
大部分图层不做实际的绘图操作。相反,图层捕获应用的内容并缓存它们到位图中。位图有时也被称为储备(backing store)。当你随后改变了一个图层的属性值,你做的所有只是改变了与图层对象相关联的状态信息。当你的更改触发了一个动画,Core Animation传递图层的位图和图层的状态给图形处理硬件。图形处理器所做的工作是使用获得的信息渲染位图,如图1-1所示,用图形处理硬件操纵位图 要比图形处理软件能获得更高的动画效果。
![](http://www.cocoachina.com/cms/uploads/allimg/131230/4196_131230103928_1.png)
因为操纵的是静态的位图,基于图层的绘图和基于视图的绘图在技术上有明显的不同。对基于视图的绘图,对视图的改变经常会触发调用视图的 drawRect:方法以重绘视图内容。但是此种方式的代价相对较高,因为它是CPU在主线程上的操作。Core Animation通过尽可能的使用图形硬件操纵缓存后的位图来避免了这种开销,从而完成相同或相似的效果。
虽然Core Animation尽可能的使用缓存后的内容,但也必须提供初始内容并不时地更新它。
基于图层的动画
图层的数据和状态信息是从图层内容的可视呈现中被分离了出来的。这种分离性给了Core Animation介入以及从旧的属性值动画到新的属性值的机会。例如改变一个图层的position属性会引起Core Animation将图层从当前的位置移动到新的具体位置。对其他属性做相似的改变将引起适当的动画效果。图1-2展示了一些可以执行在图层上的动画类 型。
![](http://www.cocoachina.com/cms/uploads/allimg/131230/4196_131230103956_1.png)
图1-2 可在图层上执行的动画类型
在动画运行期间,Core Animation使用硬件帮你完成每一帧的绘制工作。你只需要指定动画的开始点和结束点,剩下的交由Core Animation完成。如若需要,你也可以指定自定义时间信息和动画参数,如果你没有指定, Core Animation会提供适当的默认值。
图层对象定义了自己的几何结构
图层的其中一项任务就是管理自身内容的可视几何。可视几何包含关于图层内容边界、在屏幕上的位置,是否图层已被旋转、缩放,或应用了某种变换。 与视图类似,一个图层有一个frame和bound属性,你可以使用这两个属性来定位图层和它的内容。图层也有一些视图所没有的属性,比如anchor属 性,任何变换操作都是围绕该点运转的(可以理解为一个按在图层上的图钉)。图层的某些几何概念的指定方式与视图信息的指定方式也有不同。
图层使用两种类型的坐标系统
图层利用基于点的坐标系统和单位坐标系统指定内容的布局。坐标系统的选择依赖于被传达的信息类型。当指定的值是直接映射到屏幕或相对于其他图层 的坐标,比如图层的position属性,则使用基于点的坐标系统。当指定的值是相对于一些其他的值,与屏幕坐标不相关联,则使用单位坐标。比如图层的 anchorPoint属性,anchorPoint属性指定了相对于图层边界的一个点。anchorPoint属性可以更改。
基于点的坐标最常用于指定图层的尺寸和位置。可通过图层的bounds和postion属性设定图层的尺寸和位置。bound定义了图层自身的 坐标系统并包含图层在屏幕上的尺寸。position属性定义了图层相对于父坐标系统的位置。虽然图层有一个frame属性,该属性实际上是从 bounds和position属性派生而来,极少被使用。
图层的bounds和frame矩形的方向始终与底层平台的默认方向相匹配。图1-3显示了iOS和OS X平台上边界矩形的默认方向。在iOS中,默认情况下边界矩形的原点在图层的左上角。而OS X上边界矩形的原点则在左下角。如果你在iOS和OS X版本的app之间共享Core Animation代码,一定要对此种情况做区别对待。
![](http://www.cocoachina.com/cms/uploads/allimg/131230/4196_131230104017_1.png)
图1-3 iOS与OS X平台默认的图层几何结构
注意到图1-3中position属性被定位在图层的中间位置。position属性的变化参照图层的anchorPoint属性。
锚点是使用单位坐标系统的属性之一。Core Animation中使用单位坐标表示的属性值可能会因为图层的尺寸变化而发生改变。你可以把单位坐标当做是总数的百分比。在单位坐标系统空间中每一个坐 标的取值范围在0.0和1.0之间。比如说,沿着x轴,左侧是0.0,右侧是1.0.沿着y轴,单位坐标值方向的不同依赖于具体的平台。如图1-4所示。
![](http://www.cocoachina.com/cms/uploads/allimg/131230/4196_131230104052_1.png)
图1-4 iOS和OS X平台默认的单位坐标系统
注意:直到OS X 10.8才出现了geometryFlipped属性,该属性可以改变默认图层y坐标的方向。当翻转变换被调用时,使用该属性来调整图层的方向有的时候是 必需的。如果父视图使用了翻转变换,它的子视图内容(以及它对应的图层)将经常被颠倒。在这种情况下,设置子图层的geometryFlipped属性为 YES是一种修正该问题最简单的方法。在OS X 10.8及以上版本,AppKit负责管理该属性,你不应该更改它。对于iOS app,不推荐使用geometryFlipped属性。
所有的坐标值,无论是点还是单位坐标都以浮点数指定。使用浮点数允许你更精确的指定可能落在整数坐标值之间的点。特别是打印或向retina屏幕绘图,浮点值都会很方便。浮点值允许你忽略底层设备的分辨率,而你只需要指定值的精度。
锚点影响几何结构的操作
图层的几何操是相对于图层的锚点进行的,anchorPoint属性可以访问图层的锚点值。当改变图层的postion和transform属性值,锚点的影响就很明显。position属性是相对于图层的锚点被指定。并且任何你对图层阴影的变换操作也是相对于锚点。
图1-5说明了改变锚点对图层position属性的影响。尽管图层没有在它的父边界内移动,将锚点从中心点移动到图层边界的原点将改变position属性值。
![](http://www.cocoachina.com/cms/uploads/allimg/131230/4196_131230104111_1.png)
图1-5 锚点是如何影响图层的position属性
图1-6显示了锚点的变化是如何影响到应用在图层上的变换。当你对图层应用了一个旋转变换,图层将围绕中心点旋转。因为默认情况下,锚点被设定在图层的中心位置。一般创建这类旋转行为正是你所期望的。然而如果你改变了锚点值,旋转的结果也会发生变化。
![](http://www.cocoachina.com/cms/uploads/allimg/131230/4196_131230104138_1.png)
图1-6 锚点是如何影响图层的变换
图层可在三维空间中操作
图层有两个操控图层和内容的变换矩阵,transform和sublayerTransform属性。CALayer的transform属性 用来指定应用到图层和它内嵌的子层上的变换。通常当你想更改图层本身则使用该属性。比方说,你可能使用该属性缩放或旋转图层,或是临时的改变图层的位置。 sublayerTransform属性定义了仅应用在子层上的变换以及给场景内容添加透视效果。
变换行为由多个坐标确定,这些坐标通过一个数字矩阵来获取,获取的坐标结果是原始点被变换后的版本。因为Core Animation的值可在三维空间中指定,每个坐标点有四个值,这四个值需要和一个4*4的矩阵相乘。
如图1-7所示。在Core Animation中,图中的变换由CATransform3D类型表示。幸运的是,你不需要直接更改这个结构中的域值来执行标准变换。Core Animation为创建缩放、平移、旋转矩阵以及矩阵比较提供了综合的函数集。除了使用函数操纵变换。Core Animation扩展了键值编码以支持你使用键路径更改一个变换操作。
![](http://www.cocoachina.com/cms/uploads/allimg/131230/4196_131230104304_1.png)
图1-7 使用矩阵数学转换一个坐标
图1-8显示了对一些常见的变换矩的配置。任何坐标与单位矩阵相乘将返回完全相同的坐标。坐标如何被更改完全依赖于你变化的矩阵因子。比如,为 了仅在X轴上平移,你只需对变换矩阵的tx因子应用一个非零值,并让ty和tz值为0。如果是旋转,应用一个旋转角度的正弦和余弦值。
![](http://www.cocoachina.com/cms/uploads/allimg/131230/4196_131230104316_1.png)
图1-8 常见变换的矩阵配置
不同的图层树反映了不同的动画状态
使用Core Animation的app拥有三个图层对象集合。每一个图层对象集合在呈现app内容上都扮演着不同的角色。
Ø模型图层树中的对象(或简称“图层树”)用的最多。在这个树中的对象是模型对象,模型对象负责存储所有动画的目标值。无论何时改变图层的属性值,你使用的始终是某一个模型对象。
Ø呈现树中的对象包含所有运行中的动画的瞬时值。图层树对象包含的是动画的目标值,而呈现树中的对象代表显示在屏幕上动画的当前值。你不应该更改这个树中的对象。相反,你使用这些对象来读取当前动画的值,可能用于创建开始于这些值的新的动画。
Ø在渲染树中的对象执行实际的动画,并且对Core Animation是不公开的。
每一个图层对象集合被组织在一个层次结构中,类似于app中的视图。事实上,在一个所有视图都支持图层功能的app来说,每一个树的初始结构完 全与图层的层次相匹配。一个app可以添加另外的图层对象,因此图层与视图是不相关联的。可以按照需求将图层对象插入到指定的视图层级中。你可能为了优化 app内容的性能而选择加入图层对象而非视图,原因在于图层的开销要比视图低。图1-9展示了出现在一个简单iOS app的图层分解图。在示例中窗口包含了一个内容视图,内容视图包含了一个按钮视图和两个独立的图层对象。每一个视图拥有一个相对应的构成图层层次的图层 对象。
![](http://www.cocoachina.com/cms/uploads/allimg/131230/4196_131230104354_1.png)
图1-9 与窗口相关联的图层
在图层树中的每一个对象,在渲染树和呈现树中也存在一个与之匹配的对象。如图1-10所示。正如之前提到过的,app主要与图层树中的对象进行 交互,但可能有时会访问呈现树中的对象。具体地,访问图层树中对象的presentationLayer属性将返回一个在呈现树中相对应的对象。你可能会 通过该对象获取在动画执行过程中的某一时刻的属性值。
![](http://www.cocoachina.com/cms/uploads/allimg/131230/4196_131230104406_1.png)
图1-10 窗口中的图层树
重要:只在动画运行时访问呈现树中的对象。当动画在进行中,呈现树就包含了图层显示在屏幕上的那一刻的值。该行为与图层树不同,图层树永远只表示最终的目标值。
图层不是视图的替代品。因此无法创建一个基于单一图层对象的可视界面。图层是视图的基础设施。具体地,图层让视图的绘图和动画更简单和高效,并 且能在绘图和动画时保持高帧率。然而许多事情图层无法做到。图层不能处理事件、绘制内容,特别是在响应链中,或是做一些其他的事情。因此,每个app必须 有一个或多个视图来处理这类交互。
在iOS中,每一个视图有一个相对应的图层对象。但在OS X中,你必须决定哪一个视图拥有图层。OS X 10.8以及之前的版本中,添加图层到所有视图上也许是有意义的。然而你不必这样做,你仍可以关闭图层防止不必要以及无根据的开销。
图层在某种程度上减少了程序的内存开销,图层的这些优点远远超出它的缺点。所以最好是在禁用图层支持之前测试你app的性能。
当你的视图支持图层后,此时该视图被称为layer-backed视图。对于layer-backed视图,系统负责创建底层的图层对象,并保 持与视图的同步。所以iOS视图都是支持图层的并且在OS X中的大部分视图也是如此。但是在OS X中,你也可以创建图层托管(layer-hosting view)视图,该视图的图层对象由你来提供。
注意:对于layer-backed视图,建议只 操作视图而不是图层。iOS中视图仅仅是对图层对象的精简包装,所以任何你对图层的操作通常都会正常工作。但是iOS和OS X平台上操纵图层而不是图层可能不会取得预期的结果。该文档会尽可能的指出这些陷阱并提供一种方式让你可以与它们工作。
除了与视图相关的图层,你也可以创建独立的图层对象。你可以嵌入这些独立图层对象到任何其他图层对象中,包括与视图相关的图层。你一般使用图层 对象作为具体优化方法的一部分。比如说,如果你想使用相同的图片在多个地方,你可以只加载图片一次,然后将图片和多个独立的图层对象相关联,最后添加这些 图层对象到图层树中。每一个图层只会引用源图片而不是尝试在内存中创建自身对图片的拷贝。