Core Animation编程指南
|
文件状态
[
] 草稿文件
[ P] 正式文件
[ ] 更改正式文件
|
文件标识
|
|
|
当前版本:
|
1.0
|
|
|
译 者:
|
夏军
|
|
|
完成日期:
|
2013年9月1日
|
版本历史
|
版本/状态
|
译者
|
参与者
|
起止日期
|
备注
|
|
v 0.9 草稿文件
|
夏军
|
|
2013-8-13至
|
起草
|
|
|
夏军
|
|
|
润色
|
关于Core Animation
Core
Animation是iOS和OS
X平台上的图形渲染器,是动画的基础设施。你可以使用Core Animation让你应用中的可视元素与视图产生动画效果。使用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也提供了一组由视图暴露的扩展功能的接口,以使你更细粒度地控制你应用的动画效果。

一言蔽之
你可能从不需要直接使用Core Animation,但是当你使用Core Animation,你应该明白Core Animation是你应用的基础构件的一部分。
Core Animation管理你得app的内容
Core
Animation它自己不是一个绘图系统。它是一个在硬件上合成和操纵你应用内容基础构件。这个基础构件的核心是图层对象,你使用图层来管理和操控你的内容。一个图层捕获你得内容到一个你可以很容易通过图形硬件操控的位图中。在大部分的应用中,图层被作为一种管理视图内容的方式,但是你也可以创建标准的图层,这取决于你自身的需要。
相关章节:“Core Animation基础” “设置图层对象“
图层更改触发器动画
你使用Core Animation创建的大部分的动画都包含图层属性的更改。就像视图一样,图层对象也有一个边框矩形,一个屏幕上得位置,一个不透明度,一个变换,以及许多其他面向可视的属性。对于大部分这些属性,改变属性的值就会导致隐式动画被创建,通过从旧值到新值的图层动画。在你想更多控制你动画行为的时候,你也可以显示地修改动画的属性。
相关章节:“动画图层内容”,“高级动画技巧”, “图层的样式属性动画”,“可动画属性”
图层可以被组织成层次结构
图层可以被层次化地排列来创建父子关系。图层的排列影响可视内容。可视内容被一种与图层相似的方法管理。一个图层集合的层次被附加到视图上,镜像相应的视图层次。你也可以添加独立的图层到一个图层层次来扩展你软件的可视内容仅仅超出你的视图。
相关章节:“构建一个视图层次”
让你改变一个图层默认行为的动作
隐式图层动画通过使用动作对象做到,动作对象是一个实现一个预定义接口的常规对象。Core Animation使用动作对象来实现一组通常与图层相关联的动画。你可以创建你自己的动作对象来实现自定义的动画或者也可以使用动作对象来实现其他行为类型。你接着赋值你的动作对象到图层的其中一个属性。当属性发生变化,Core Animation检索你的动作对象并告诉动作对象执行它的动作。
相关阅读:“改变图层的默认行为”
如何使用该文档
该文档为需要更多的操控软件的动画效果或者想要使用图层来提升软件绘图性能的开发者准备。该文档也讲述了在iOS和OS X平台上对图层和视图进行整合的信息。图层和视图的整合在iOS和OS X平台上是不同的,理解这些不同对于创建高效的动画至关重要。
先决条件
你应该已经理解了你的目标平台的视图架构以及熟悉如何创建基于视图的动画。如果你还未到该阶段,请阅读一下两篇文档:
对于iOS软件的开发,你应该理解《iOS视图编程指南》中关于视图架构的描述。
对于OS X软件的开发,你应该《视图编程指南》中关于视图架构的描述。
另请参阅
对于如何通过Core Animation来实现指定类型动画的示例可参考《Core Animation
Cookbook》。
Core Animation基础
Core Animation为动画视图和其他你应用中得可视元素提供了一个通用系统。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所示,用图形处理硬件操纵位图要比图形处理软件会得到更快的动画效果。

因为操纵的是位图,基于图层的绘图和基于视图的绘图技术上有很大的不同。对基于视图的绘图,改变视图经常会调用视图的drawRect:方法来使用新参数重绘内容。但是使用这种方式代价高,因为它是使用CPU在主线程上进行操作。Core Animation通过尽可能的使用图形硬件操纵缓存后的位图来避免了这种开销,从而完成相同或相似的效果。
虽然Core Animation尽可能的使用缓存后的内容,你的软件也必须提供初始内容并不时地更新它。有多种方式提供带有内容的图层对象,更多细节请参阅:“图层内容的提供”。
基于图层的动画
一个图层对象的数据和状态信息与呈现在屏幕上的图层的内容是相分离的。分离的状态让Core
Animation可以干预自己,以及以动画的形式将状态值从旧值变化到新值。例如改变一个图层的position属性会引起Core Animation将图层从当前的位置移动到新的具体位置。对其他属性做相似的改变将引起适当的动画效果。图1-2说明了一些你可以在图层上执行的一些类型的动画效果。有关图层的动画触发属性列表,可参见“动画属性”(page..)

图1-2 有效的图层动画
在动画运行期间,Core Animation使用硬件帮你完成每一帧的绘制工作。你只需要指定动画的开始点和结束点,剩下的交由Core Animation完成。如若需要,你也可以指定自定义时间信息和动画参数,如果你没有指定, Core Animation会提供适当的默认值。
关于初始化动画以及配置动画参数的相关内容可参见“动画图层的内容”。
图层对象定义他们自己的几何
图层的其中一项任务就是管理自身内容的可视几何。可视几何包含关于图层内容边界、在屏幕上所处位置,是否图层已被旋转、缩放,或者做了某种变换。与视图类似,一个图层有一个frame和bound属性,你可以使用这两个属性来定位图层和它的内容。图层也有一些视图所没有的属性,比如anchor属性,anchor锚点定义了一个围绕操控发生的固定点(可以理解为一个按在图层上的图钉)。指定图层几何的一些概念的方式也和指定视图信息的方式不一样。
图层使用两种类型的坐标系统
图层利用基于点的坐标系统和单位坐标系统指定内容的布局。坐标系统的选择依赖于被传达的信息类型。当指定的值是直接映射到屏幕或相对于其他图层的坐标,比如图层的position属性,则使用基于点的坐标系统。当指定的值和屏幕坐标不相关联,因为它相对于一些其他的值,则使用单位坐标。如图层的anchorPoint属性指定了相对于图层自身边界的一个点,改点可做改变。
基于点的坐标最常用于指定图层的尺寸和位置。可通过图层的bounds和postion属性设定图层的尺寸和位置。bound定义了图层自身的坐标系统并包含图层在屏幕上的尺寸。position属性定义了图层相对于父坐标系统的位置。虽然图层有一个frame属性,该属性实际上是从bounds和position属性派生而来,且极少被使用。
图层的bounds和frame矩形的方向始终和底层平台的默认方向相匹配。图1-3显示了iOS和OS X平台上边界矩形的默认方向。在iOS中,默认情况下,边界矩形的原点在图层的左上角。而OS X上边界矩形的原点则在右下角。如果你在iOS和OS X版本的app之间共享Core Animation代码,那你必须区别对待。

图1-3 iOS与OS X平台默认的图层几何结构
注意到图1-3中position属性被定位在图层的中间位置。position属性的变化依据图层中anchorPoint属性。anchor锚点表示由该点确定的坐标原点。更多细节描述于“锚点影响几何结构的操作”。
锚点是几个使用单位坐标系统的属性之一。Core Animation使用单位坐标表示的属性值可能会因为图层的尺寸变化而发生改变。你可以把单位坐标当做是总数的百分比。在单位坐标系统空间中每一个坐标的取值范围在0.0和1.0之间。比如说,沿着x轴,左侧是0.0,右侧是1.0.沿着y轴,单位坐标值方向的不同依赖于具体的平台。如图1-4所示。

图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属性值。
图1-5 锚点是如何影响图层的position属性
图1-6显示了锚点的变化是如何影响对应用于图层的变换。当你对图层应用了一个旋转变化。旋转是围绕锚点发生的。因为默认情况下,锚点被设定在图层的中间位置。一般创建这类旋转行为正是你所期望的。然而,如果你改变了锚点,旋转结果将会不同。

图1-6 锚点是如何影响图层的变换
图层能在三个维度上操作
每个图层都有两个变换矩阵,你可以用来操作图层和它的内容。CALayer的transform属性用来指定应用到图层和它内嵌的子层上的变换。通常当你想更改图层自己则使用该属性。比方说,你可能使用该属性缩放或旋转图层,或是临时的改变他的位置。sublayerTransform属性定义了仅引用到子层的变换,常用于对场景内容加入透视效果。
变换的行为由多个坐标确定,通过一个数字矩阵来获取新的坐标。新的坐标是原始点被变换后的版本。因为Core Animation的值可在三个维度上指定,每个坐标点有四个值,这四个值需要和一个4*4的矩阵相乘。如图1-7所示。在Core Animation中,图中的变换由CATransform3D类型表示。幸运的是,你不需要直接更改这个结构中的域值来执行标准变换。Core Animation为创建缩放、平移、旋转矩阵以及矩阵的比较提供了一个综合的函数集。除了使用函数操纵变换。Core Animation扩展了键值编码以支持你使用键路径更改一个变换操作。你可以更改的键路径列表,可参阅“CATransform3D键路径”

图1-7 使用矩阵数学转换一个坐标
图1-8显示了对一些常见的变换矩的阵配置。任何坐标与单位矩阵相乘将返回完全相同的坐标。其他的变换,坐标如何被更改完全依赖于你改变的矩阵因子。比如,为了仅在X轴上平移,你将对变换矩阵的tx因子应用一个非零值,并让ty和tz值为0。如果是旋转,你提供一个适当的目标旋转角度的正弦和余弦值。

图1-8 常见变换的矩阵配置
关于用于创建和操作变换的函数的介绍参见“Core Animation Function Reference”。
不同的图层树表示不同的动画状态
使用Core Animation的app拥有三个图层对象集合。每一个图层对象集合在呈现app内容上都扮演着不同的角色。
l 在模型图层树中的对象(或简称“图层树”)用的最多。在这个树中的对象是模型对象,模型对象负责存储所有动画的目标值。无论何时改变图层的属性值,你使用的是某一个模型对象。
l 在呈现树中的对象包含所有运行中的动画的动态值。尽管图层树对象包含对动画的目标值,而呈现树中的对象代表显示在屏幕上的当前值。你不应该更改这个树中的对象。相反,你使用这些对象来读取当前动画的值,可能用于创建开始于这些值的新的动画。
l 在渲染树中的对象执行实际的动画,并且对Core
Animation是不公开的。
每一个图层对象集合被组织近一个层次结构中,类似于app中的视图。事实上,对于在一个对所有视图都开启图层功能的app中,每一个树的初始结构完全与图层的层次相匹配。然而,一个app可以添加另外的图层对象。因此,图层与视图是不相关联的。可根据需要选择图层对象所要插入的视图层次。你可能为了优化app内容的性能而选择加入图层对象而非视图,原因在于图层的开销要比视图低。图1-9展示了出现在一个简单iOS app的图层分解图。在示例中窗口包含了一个内容视图,内容视图包含了一个按钮视图和两个独立的图层对象。每一个视图拥有一个构成图层层次的相对应的图层对象。

图1-9 与窗口相关联的图层
在图层树中的每一个对象,在渲染树和呈现树中也存在一个与之匹配的对象。如图1-10所示。正如之前提到过的,app主要与图层树中的对象进行交互,但可能有时会访问呈现树中的对象。具体地,访问图层树中对象的presentationLayer属性将返回一个在呈现树中相对应的对象。你可能会通过该对象获取在动画执行过程中的某一时刻的属性值。

图1-10 窗口中的图层树
|
重要:你应该仅在动画在运行时访问呈现树中的对象。当动画在进行中,呈现树就包含了图层显示在屏幕上的那一刻的值。该行为与图层树不同,图层树永远只表示最终值。
|
图层与视图的关系
图层不是视图的替代品。因此你不可能创建一个基于单一图层对象的可视界面。图层是视图的基础设施。具体地,图层让视图的绘图和动画更简单和高效,并且能在绘图和动画时保持高帧率。然而,许多事情图层无法做到。图层不能处理事件、绘制内容,特别是在响应链中,或是做一些其他的事情。因为这个原因,每一个app必须仍旧有一个或更多的视图来处理这类交互。
在iOS中,每一个视图有一个相对应的图层对象提供支持。但在OS X中,你必须决定哪一个视图拥有图层。在OS X 10.8以及之前的版本中,添加图层到所有视图上也许是有意义的。然而你不必这样做,你仍可以关闭图层防止不必要以及无根据的开销。
图层在某种程度上减少了你程序的内存开销,图层的这些优点经常超出他们的缺点。所以最好是在禁用图层支持之前测试你app的性能。
当你开启视图对图层的支持,你创建的视图即被称为支持图层的视图(layer-backed view)。在一个支持图层的视图中,系统负责创建底层的图层对象,并保持与视图的同步。所以iOS视图都是支持图层的并且在OS X中的大部分视图也是如此。但是,在OS X中,你也可以创建图层托管(layer-hosting view)视图,该视图的图层对象由你来提供。
|
注意:支持图层的视图,建议你无论何时尽量操作视图而不是它的图层。在iOS中,视图仅仅是对图层对象的精简包装,所以任何你对图层的操作通常都会正常工作。但是iOS和OS X平台上操纵图层而不是图层可能不会取得预期的结果。只要有可能,该文档将指出这些陷阱并提供一种方式让你可以与它们工作。
|
除了与视图相关的图层,你也可以创建独立的图层对象。你可以嵌入这些独立图层对象到任何其他图层对象中,包括与视图相关的图层。你一般使用图层对象作为一个特殊优化路径的一部分。比如说,如果你想使用相同的图片在多个地方,你可以只加载图片一次,然后与多个独立的图层对象相关联,最后添加这些图层对象到图层树中。每一个图层接着引用源图片而不是尝试在内存中创建自身对图片的拷贝。
更多关于如何开启对图层的支持信息,请参阅“在你的app中开启对Core Animation的支持”。更多关于如何创建图层对象结构层次和可能会用到的技巧,请参见“构建一个图层结构层次”。
设置图层对象
图层对象是你使用Core Animation做任何事情的关键。图层管理app的可视内容,提供更改内容样式和可视外观的选项。虽然iOS app自动对图层进行支持。OS X的开发者必须在利用图层在性能上的优势之前显式地开启对图层的支持。一旦开启对图层的支持,你必须能理解如何配置和操控你app中的图层以获得你想要的效果。
在你的App中开启对Core Animation的支持
在iOS app中,Core Animation总是开启的,每一个视图都是支持图层的。在OS X中,app必须显示地通过以下方式开启对Core Animation的支持:
l 对QuartzCore框架进行链接(iOS app如果使用了Core Animation则必须显式地链接到该框架)。
l 对一个或多个NSView开启对图层的支持通过以下方式之一完成:
l 在你的nib文件中,使用View Effect检视面板以开启视图对图层的支持。检视面板会对选中的视图和它的子视图显示一个复选框。推荐做法是尽可能的在窗口的内容视图中开启对图层的支持。
l 对于编码创建的视图,调用视图的setWantsLayer:方法,并传入一个YES值以表明视图应该使用图层。
使用前述的方式开启对图层的的支持以创建一个支持图层的视图。系统负责创建视图底层的图层对象,并保持对图层的更新。在OS X中,也可以创建图层托管的视图,该视图底层的图层由你的app创建和管理(你不能在iOS中创建图层托管视图)。更多关于如何创建图层托管视图的信息可参阅“在OS X中图层托管让你改变图层对象”。
改变与图层相关联的图层对象
支持图层的视图默认会创建一个CALayer实例,一般情况下你可能不需要不同类型的图层对象。但是Core Animation提供了不同类型的图层类,不同图层类型提供了自身特殊的功能。选择一个不同的图层类可能会提升你的性能或是以一种简单的方式支持一种具体的内容类型。比如CATiledLayer类在显示大图片上使用高效的方式做了优化。
改变视图所持有的图层类
你可以通过覆盖iOS视图中的layerClass方法并返回一个不同类对象以改变图层的类型。大部分的iOS视图创建一个CALayer对象并使用图层作为对自身内容的后备存储。对于大部分你拥有的视图,默认的选择是好的,并且你不需要在改变它。但是你可能找到一个不同类型的视图。但是你可能会再某些具体的情况下更适合的不同图层类。比如,你可能在以下情况下需要改变图层类的类型:
l 你的视图的绘图内容是由OpenGL
ES实现,在此种情况下你将使用CAEAGLLayer对象。
l 一个特殊的图层拥有更强的表现性能。
l 你想利用某些特殊的Core
Animation类,比如粒子发射器或者复制器。
改变一个视图的图层类非常简单;清单2-1显示了这个例子。所有你需要做得只是覆盖layerClass方法并返回一个你想要替代的类对象。如你看到的,视图调用layerClass方法并使用返回的类为其创建新的图层对象。一旦创建完成,视图的图层对象将不可改变。
清单2-1 一个iOS视图图层类的指定
|
+(Class) layerClass
{
return [CAEAGLLayer class];
}
|
图层类的列表清单以及如何使用它们可参阅“不同图层类提供的特殊行为”。
改变NSVIew使用的图层类(略)
在OS X中使用图层托管改变图层对象(略)
Core Animation定义了许多标准的图层类,每一个图层类都有着各自的应用场景。CALayer类是所有图层对象的根类,它定义了所有图层对象必须支持的行为,它也是支持图层的视图的默认使用类型。但你也可指定表2-1中的某一个图层类。
|
类别
|
用途
|
|
CAEmitterLayer
|
用于实现基于Core Animation粒子发射系统。发射器层对象控制粒子的生成和起源
|
|
CAGradientLayer
|
用于绘制一个颜色渐变填充图层的形状(所有圆角矩形边界内的部分)
|
|
CAEAGLLayer/CAOpenGLLayer
|
用于设置后备存储和上下文需要使用OpenGL ES(iOS)或OpenGL(OS X)绘制。
|
|
CAReplicatorLayer
|
当你想自动生成一个或多个子层的拷贝。复制器为你生成拷贝并使用你指定的属性值以修改复制品的外观和属性。
|
|
CAScrollLayer
|
用于管理由多个子区域组成的大的可滚动区域
|
|
CAShaperLayer
|
用于绘制三次贝塞尔曲线。形状图层对绘制基于路径的形状是有帮助的。因为形状图层总是生成一个最新的路径。与此相反,将路径绘制到图层的后备存储中,当图层被缩放后,效果就不那么好了。而最新的路径结果所做的包括在主线程中渲染形状以及缓存结果。
|
|
CATextLayer
|
用于渲染一个无格式或属性的文本字符
|
|
CATransformLayer
|
用于渲染一个真实3D图层层级。而不是其他图层类实现的扁平化图层层级。
|
|
QCCompositionLayer
|
用于渲染一个Quartz生成元素(仅在OS X中有效)
|
不同的图层类提供特殊的行为
l 图层是管理由你的app提供的数据对象内容。一个图层的内容由一张包含你想显示的可视数据位图构成。你可以使用下列三种方式之一来给图层提供内容:
l 直接赋值图片对象到图层对象的contents属性上。(这个技术适用于图层内容从不或几乎不改变的情况下。)
l 赋值一个代理对象给图层并让代理绘制图层的内容。(该技术适用于图层内容可能偶尔改变,并可被外部的对象提供,如视图。)
l 定义一个图层子类或覆盖他的绘图方法中的一个以提供图层的内容。(该技术适用于如果你必须创建一个自定义的图层子类或如果你想去改变图层基本的绘图行为。)
你需要为提供图层内容而担心的时刻只在手动创建图层对象的时候。如果你的app中只包含支持图层的视图。那你不需要担心使用刚刚提到的这些提供图层的方法提供图层内容。支持图层的视图会使用尽可能高效的方式为与之相关的图层提供内容。
使用图片为图层提供内容
因为一个图层仅仅是为了管理位图图片的容器,你可以直接赋值一个图片给图层的contents属性。赋值一个图片给图层很简单,只需要指定一张你想显示在屏幕上的具体的图片就可以了。图层将直接使用你提供的图片对象,不会尝试创建自己的图片拷贝。当你的应用使用相同的图片在多个地方时这个行为可以节省内存。
你赋值的图片类型必须是CGImageRef类型(在OS X 10.6或之前版本,你也可以赋值一个NSImage对象。)当赋值图片时,记住提供的图片的分辨率要与本地设备的分辨率相匹配。对于Retina显示设备,这可能也需要你去调整图片的contentsScale属性。关于如何使用高分辨率的图层内容,可参阅“使用高分辨率的图片”。
使用代理提供图层的内容
如果图层的内容是动态改变的,你可以使用一个代理对象在需要的时候提供和更新图层内容。在显示的时候,图层调用你的代理方法以提供需要的内容:
l 如果你的代理实现了displayLayer:方法,实现负责创建位图并赋值给contents属性。
l 如果你的代理实现的是drawLayer:inContext:方法,Core Animation创建一个位图,创建一个绘制到位图中得图形上下文,并调用你的代理方法填充该位图。你的代理方法所要做的是将内容往提供的图形上下文绘制。
代理对象必须实现displayLayer:或者drawLayer:inContext方法之一。如果代理对象把这两个方法都实现了,图层只调用displayLayer:方法。
覆盖displayLayer:方法在当你的app更倾向于载入或创建想要显示的位图的情况下适用。清单2-3显示了一个实现displayLayer:代理方法的示例代码。在这个例子中,代理使用了一个辅助对象来加载和显示它需要的图片。代理方法根据内部的状态选择那张图片显示。例子中得displayYesImage是一个自定义的属性。
清单2-3:直接设置图层的内容
|
- (void)
displayLayer:(CALayer *)theLayer {
//检查某些属性状态值
if
(self.displayYesImage) {
// 显示Yes图片
theLayer.contents
= [someHelperObject loadStateYesImage];
}
else {
// 显示No图片
theLayer.contents = [someHelperObject
loadStateNoImage];
}
}
|
如果你没有预渲染的图片或者辅助对象来创建位图。代理对象可以使用drawLayer:inContext:方法动态的绘制内容。清单2-4显示了一个对drawLayer:inContext方法实现的例子。在该例子中,代理对象使用了固定的宽度和当前的渲染颜色绘制了一个简单的曲线路径。
带有自定义内容的支持图层的视图,你应该去覆盖视图的绘图方法。一个支持图层的视图自动创建它自己的图层代理并实现需要的代理方法,你不应该改变这个配置。相反,你应该实现你视图的drawRect:方法以绘制你的内容。
在OS X 10.8和之前的版本中,绘图的另外方法是通过覆盖你视图的wantsUpdateLayer和updateLayer方法提供一个位图。覆盖wantsUpdateLayer并返回YES会引起NSView类调用替换的渲染路径。相对于调用drawRect:方法,视图调用你的updateLayer:方法,方法的实现必须直接赋值一个位图给图层的contents属性。这个AppKit期望你直接设置视图的图层对象内容的一种方案。
使用子类化提供图层内容
如果你实现了一个自定义的图层类。你可以覆盖图层类的绘图方法做任何绘图的操作。用这种方法生成图层对象的自定义内容是罕见的。但是某些图层可以管理显示的内容。如CATiledLayer类通过将大图片拆成更小的可管理、可独立渲染的碎片来管理大的图片。因为只有图层知道在某一时刻哪一个碎片需要被渲染。图层直接管理绘图行为。
当子类化图层类,你可使用下述的两种方式绘制你的图层内容:
l
覆盖图层的display方法并使用在方法中直接设置图层的contents属性。
l
覆盖图层的drawInContext:方法并将需要的内容绘制到提供的图形上下文中。
选择何种方法依赖于在绘图过程中你需要多少的控制。display方法是更新图层内容的主要入口点,所以覆盖这个方法让你处于完全的过程控制中。覆盖display方法也意味你需要负责contents属性创建CGImageRef对象。如果你只是想绘制内容(或让你的图层管理绘图操作),你可以覆盖drawInContext:方法并让图层为你创建后备存储。
调整提供的内容
当给图层的contents属性赋值一个图片时,图层的contentsGravity属性确定图片如何操控以适合当前的边界。默认情况下,如果一个图片大于小于当前的边界,图层对象缩放图片以适应有效的空间。如果图层的长宽比和图片的长宽比不一致,这会导致图片被扭曲。你可以使用contentsGravity属性来确定你的内容以最佳的方式被呈现。
你可以向contentsGravity属性赋予的值分为两个分类:
l
基于位置的引力约束允许你固定你的图片到图层矩形边界的一个特殊的边缘或角落,不会缩放图片。
l
基于缩放的引力约束允许你伸缩图片使用多个选项之一,某些选项保留长宽比,有些则不保留。
图2-1 显示了基于位置的引力设置如何影响你的图片。除了kCAGravityCenter约束,每一个约束都将图片固定在图层矩形边界的某个边缘或角落。kCAGravityCenter约束将图片居中在图层中。基于位置的引力约束没有一个选项会缩放图片。所以图片总是和它原始的尺寸一样的情况下被渲染。如果你的图片大于图层的边界,这可能导致部分图片被裁减;如果图片小于矩形边界,则图片没有覆盖到得区域则显示图层的背景颜色,如果设置了背景颜色的话。

图2-1 基于位置的图层引力约束
图2-2显示了基于缩放的引力约束如何影响你的图片。如果图片不是准确匹配图层矩形边界范围内,所有这些约束都会缩放你的图片。这些模式选项之间所不同的是如何处理图片原始的长宽比。一些模式保留原始图片的长宽比,有些则不保留。默认情况是,图层的contentsGravity属性被设置为kCAGravityResize常量值,它是唯一一个不保留图片的长宽比的选项。

图2-2 基于缩放的图层引力约束
使用高分辨率的图片
图层没有任何固有关于底层设备分辨率的知识。图层简单的存储一个对位图的指针并用给定的有效像素以最佳的方式显示它。如果你赋值一个图片给图层的contents属性,你必须通过设置图层的contentsScale属性一个正确的值以告诉Core Animation关于图片分辨率。默认的属性值为1.0,对于在标准分辨率的屏幕上显示图片是正确的。如果你的图片要在Retina屏幕上显示,该值需要设定为2.0.
如果直接赋值一副位图给你的图层的情况下,改变contentScale属性的值才是必须的。在UIKit或AppKit中,一个支持图层的视图会被自动设置基于屏幕分辨率的图层缩放因子,并且图层内容由视图管理。
在OS X中,基于位置的引力约束影响图片呈现的方式。从NSImage对象选择赋值给图层。因为这些实例不会引起图片的缩放。Core Animation依靠contentsScale属性以最佳的像素密度呈现图片。
在OS X中,图层的代理可以实现layer:shouldInheritContentScale:fromWindow:方法,使用该方法响应对缩放因子的改变。可能因为窗口会在标准分辨率和高分辨率屏幕之间移动,AppKit会在窗口分辨率变化时自动调用代理的实现方法。如果代理支持图层的图片分辨率的变化,则此方法返回YES。当需要反映分辨率的变化,该方法会更新图层的内容。
调整图层的可视样式和外观
图层对象拥有内建的可视装饰,比如边框、背景色。你可以使用这些装饰对图层主要内容进行补充。因为这些可视的装饰不需要任何装饰。装饰让图层在一些情况下成为标准的实体成为可能。你只需设置图层的属性,图层自会处理必要的绘图工作,包括动画。关于这些装饰如何影响你的图层外观的信息的说明请参阅:“图层风格属性动画”。
图层拥有自己的背景和边框
图层除了可以显示基于图片的内容,还可以显示被填充的背景、描边的边框。背景被渲染在图层的内容图片的后方,边框被渲染在内容图片的前方。如图2-3显示。如果图层包含子层,子层也会显示在边框的下方。因为背景颜色是处在图片的后方的,背景会从图片的任何透明的地方透射出来。

图2-3 给图层添加边框和背景色
清单2-5显示了设置图层的边框和背景颜色代码。所有的这些属性都是可动画的。
|
myLayer.backgroundColor
= [NSColor greenColor].CGColor;
myLayer.borderColor
= [NSColor blackColor].CGColor;
myLayer.borderWidth
= 3.0;
|
|
注意:你可以将图层的背景设置成任何颜色,包括支持透明的颜色或使用模式图片。使用模式图片时,渲染是由Core Graphics完成,它使用的是标准坐标系统。标准坐标系统和iOS的坐标系统是不一样的。所以,图片在iOS上得渲染结果是颠倒的。可以使用[backgroundLayer
setTransform:CATransform3DMakeScale(1.0, -1.0, 1.0)];解决该问题。
|
如果你将图层的背景颜色设置为不透明。考虑将图层的opaque属性设置为YES。当合成屏幕上的图层时可以提升系能,同时也会消除图层的后备存储管理alpha通道的要求。如果你给图层设置了非零的圆角半径,则不可以将图层标记为不透明类型。
图层支持圆角半径
你可以通过给图层添加一个圆角半径来创建一个圆角矩形。圆角半径是一个可视的装饰,它遮罩了图层边界矩形的部分区域以允许底层内容的显示。如图2-4所示,因为它包括了应用一个透明蒙版,圆角半径不影响图层的contents属性中得图片,除非masksToBounds属性被设置为YES。然而,圆角半径总是影响图层的背景颜色和边框的绘图方式。

图2-4 图层的圆角半径
图层支持内建阴影
CALayer类包括若干个配置阴影的属性。阴影让图层更加有深度,好像图层浮起来了。阴影也是另一种装饰。在具体的环境你会发现阴影非常的有用。使用图层,你可以控制阴影的颜色,相对于图层内容的位置,透明度以及形状。
图层阴影的阴影透明度shadowOpacity默认被设置为0,这有效地隐藏了阴影。改变透明度为非0值将引起Core Animaiton绘制阴影。因为默认情况下,阴影被直接定位在图层的下方。所以你可能为了能够看到阴影而改变阴影的偏移量。记住这个很重要。你指定的偏移量被应用到图层上使用的是图层的本地坐标系。本地坐标系在iOS和OS X上的表现是不同的。如图2-5所示,图中显示了一个带有偏下偏右阴影的图层。在iOS中,这需要指定一个正值,而在OS X中需要指定一个负值。

图2-5 给图层设置阴影
给一个图层的contents属性赋值一张只有中间部分存在图像四周为透明的图片,并对图层施加阴影,阴影的偏移量为(5,5)。则该阴影只会出现在红色圆的偏右偏下出现。如果给图层施加了backgroundColor值,则此时的阴影就会出现在图层边界的偏右偏下方。图层产生阴影的条件包括设置图层的shadowOffset属性值、shadowOpacity属性值、图层或其子层的contents属性值或者backgroundColor属性值。

图2-6 四周透明的图片
当给图层添加阴影,阴影就是图层内容的一部分但是实际上阴影扩展到了图层边界矩形的外围。结果是,如果你启用了图层的masksToBounds属性,围绕边缘的阴影将被裁减掉。如果你的图层中含有任何透明的内容,这将引起一个古怪的效果,图层下方的阴影部分依然可以看见,但是超出图层边界的部分就没有了。如果既想要阴影又要启用maskToBounds为YES,那么你可以使用两个图层。第一个是包含内容的图层,将该图层的maskToBounds属性设置为YES,然后创建一个相同尺寸且含有阴影效果的第二个图层,最后调用第二个图层的addSublayer方法将第一个图层嵌入到第二个图层中就可以了。
如何对图层添加阴影的例子可参见“阴影属性”(第82页)
滤镜为OS X平台的视图添加可视效果(略)
|
注意:iOS平台上不能给图层添加滤镜
|
给图层添加自定义属性
CAAnimation和CALayer类扩展了键值编码以对自定义属性进行支持。你可以使用该行为给图层添加数据并使用你定义的键检索对应的值。你甚至可以给你的自定义属性关联动作,当该属性的值发生变化,对应的动画将会被执行。
关于如何设置和自定义属性的内容,可参阅““Key-Value Coding
Compliant Container Classes”(第90页)。更多关于如何给图层添加动作的内容,可参阅“改变图层的默认行为”(地70页)。
打印支持图层的视图内容
在打印过程中,当需要适应打印环境时图层重绘它们的内容。尽管当向屏幕上做渲染的时候,Core Animation一般依赖缓存位图。当在打印时,他重绘这些内容。特别情况下,如果支持图层的视图使用drawRect:方法提供图层内容,Core Animation将再次调用drawRect:方法以生成可打印的图层内容。
给图层的内容增添动画效果
Core Animation为轻松创建图层的动画效果,以及扩展自身拥有图层的视图提供了基础构件。包括改变图层框架矩形的尺寸,改变其在屏幕上的位置,引用旋转变换,亦或是改变它的透明度。使用Core Animation,初始化一个动画一如改变属性一样简单,当然你也可以显式的创建动画并设置动画的参数.
关于创建更多的高级动画信息可参阅:“高级动画技巧”(第63页)。
通过改变图层的属性产生动画效果
根据你的需要,你可以以显式或隐式的方式执行简单的动画。隐式动画使用默认的定时器和动画属性展现动画效果。然而显式动画需要你为动画对象配置一些参数。所以当默认的定时器能够很好的为你服务并且你所要的动画效果不需要太多代码的情况下,隐式动画则非常适合你。
简单的动画包括对图层属性的改变以及随着时间的推移,让Core Animation以动画的形式展现这些属性的变化。图层定义了许多影响图层可视外观的属性。改变这些属性中的某一个是以动画方式展现外观变化的一种方式。比如将图层的1.0透明度修改为0.0,这将引起图层的淡出特效,进而变成透明。
|
重要:虽然你可以使用Core Animation接口直接动画支持图层的视图,做这些通常需要的额外的步骤。关于Core Animation如何与支持图层的视图协同使用,可参阅“如何让支持图层的视图产生动画效果”。
|
为了处罚隐式动画,你所需做得是更新图层对象的属性。当在图层树中更改图层对象时,你的改变将立即反映到这些对象上。然而,图层对象的可视外观不会立即变化,Core Animation使用你的改变作为创建与计划一个或多个隐式动画用以执行的触发器。