Core Animation Programming Guide - Core Animation Basics

Core Animation Basics

Core Animation 为你的 app 提供视图和其他视觉元素的一般动画创建。Core Animation 并不是替代你 app 的视图,它是一种集成在视图中为视图内容提供更好性能和支持的动画技术。它通过缓存视图内容到位图实现,可以直接地被图形硬件操作。有时这种缓存行为需要你多次考虑怎么呈现和管理你 app 的内容,但是多数时候你使用 Core Animation 并不需要知道这种缓存技术。除了缓存视图内容,Core Animation也定义一种方式来明确任意的视图内容,并集成此内容到你的视图中和其他的一起表现动画。

你用 Core Animation 把 app 视图和可视对象的变化用动画的形式表现出来,大多数都是通过修改视图的属性,比如,你可能使用 Core Animation 更新视图的position,size或者 opacity。Core Animation 根据你指定的属性值和现有值的不同形成动画。你不需要想卡通动画那样每秒60次的替换视图内容,只需要在屏幕中移动视图、淡入淡出视图内容,应用任意的图形形态到视图,或者改变视图的可视属性。

Layers Provide the Basic for Drawing and Animations

Layer 对象 是在3D空间中组织成的2D界面,是Core Animation 的核心。像视图一样,layer 管理着几何、内容和界面的可视属性之类的信息。不同于视图的地方是它并不定义自己的形态。一个 Layer 仅仅管理围绕着位图的状态信息。位图本身既可以是视图的最终绘制形态,也可以是一张你指定的图片。因此,你在 app 中使用的核心 layer 主要管理的是数据,可以当做数据模型。这一点需要谨记,它会影响到动画的效果。

The Layer-Based Drawing Model

在你的 app 中,大部分的 layer 并不做实际的绘制,只捕捉 app 提供的内容并缓存它们到位图中,此位图有时被作为 backing store 。缓存到位图之后修改 layer 的属性,实际修改的都是 layer 对象相关的状态信息。当 layer 的属性值变更触发动画时,Core Animation 传递 layer 的位图和状态信息给图形卡,图形卡根据状态信息渲染位图,如图 1-1 。用硬件渲染位图比在软件中快很多。

图 1-1 How Core Animation draws content

由于是直接操作静态的位图,layer-based 的绘制技术完全不同于 view-based 的绘制技术。view-based 绘制,是视图改变后调用自身的方法 drawRect: 根据新的参数重绘,这种方式会降低性能,因为重绘的动作是通过 CPU 计算后在主线程上完成的。Core Animation 通过图形卡操作缓存的位图分担了CPU的负担来完成形似或相同的效果。

尽管 Core Animation 尽可能的使用缓存内容,你的 app 还是得提供内容的初始化和一次次的更新。Providing a Layer's Contents 这一章节中会详细地描述怎么为你的 app 提供 layer 内容对象。

Layer-Based 动画

layer 对象的数据和状态信息从屏幕的内容呈现中解耦出来。这种解耦为 Core Animation 提供了一种方式插入到自身,并以动画的形式展现状态值的变更。例如,修改 layer 的position 属性会导致 Core Animation 把 layer 从当前位置移动到新的位置。其他属性的修改也会产生类似的动画。图 1-2 展示了几种你可以在 layer 中表现的动画类型。在 Animatable Properties中列出了可以触发动画的 layer 属性。

Figure 1-2 Examples of animations you can perform on layers

在一次动画期间,Core Animation 在硬件上为你绘制了所有的图形框架。你所需要做的只是明确动画的起始点。同样地你也可以可以根据需要自定义动画的参数和时间,如果你没有自定义这些参数和时间,Core Animation 会提供合适的缺省值。

怎么初始化、配置动画参数的信息,详见 Animating Layer Content

Layer Objects Define Their Own Geometry

layer的其中一项工作就是根据其内容管理视觉几何图形。可视几何图形包括各种信息,诸如内容的 bounds、在屏幕上的 position,以及layer是否已经发生旋转、缩放、变形。像视图一样,layer 也有可以用来定位和展现内容的 frame、bounds。layer 也有一些视图不具有的属性,像定义操作发生点的 anchor point。一些列举 layer 几何图形的方面是明显不同于视图的。

Layers Use Two Types of Coordinate Systems

layer 利用 point-based coordinate systmes(基于点的坐标系统)和unit coordinate systems(单元坐标系统)明确内容的放置。坐标系统的使用依据被传递的信息类型。Point-based 坐标在有明确的屏幕坐标值或被明确地关联到另个一 layer 时使用,例如 layer 的 position 属性。Unit 坐标在属性值和屏幕坐标无关联但和其他有关联时使用,例如,layer 的 anchorPoint 坐标,它指出了一个和 layer 自身的bounds关联且可以修改的点。

point-based 坐标大多数时候通过 layer 的 bounds 和 position 属性明确 layer 的 size 和 position。bounds 定义了 layer 的坐标系统,包含 layer 在屏幕上的尺寸。position 属性定义了layer相对于父层坐标系统的定位。尽管 layer 有 frame 属性,其实 frame 源于 bounds 和 position 两个属性,使用的频次不高。

layer 的 bounds 和 frame 方向和平台的默认方向相匹配。图 1-3 展示了bounds 和 frame 在 ios 和 os x上的默认方向。ios中,bounds的原点方向默认在 layer 左上角,而 os x 中默认在左下角。如果你在 ios 和 os x 之间共享 Core Animation 的相关代码,需要注意两个平台的这点差异。

Figure 1- 3 The default layer geometries for iOS and OS X

在图 1-3 中需要注意一点,position 属性被定位在 layer 的正中间,这个属性值的明显变化是众多基于 layer 的 anchorPoint 属性值之一。锚点代表确定的坐标原点的点,在 Achor Points Affect Geometric Manipulations 中有详细的概述。

锚点是众多使用 unit 坐标系统来确定属性值的属性之一。在 layer 的 size 属性改变时会影响一些属性的改变,unit 坐标系统在Core Animation 中就是用来代表这些属性的。你可以认为 unit 坐标就是可能值的具体百分比。在 unit 坐标控件中每一个坐标的范围是 0.0~1.0 。例如,在 x 轴方向上,左边距的坐标是 0.0,右边距则是 1.0 。在 y 轴方向上,unit 坐标值的变化取决于平台,如果 1-4 所示。
Figure 1-4 The default unit coordinate system for iOS and OS X


注意:在 OS X 10.8之前,geometryFlipped 属性可以在需要的时候修改 y 轴的默认方向。当 layer 包含翻转变化时layer就需要这个属性来修改方向。例如,如果父视图使用了翻转变形,它的子视图(他们相关的layer)将常常被倒置,在这时 设置子视图们的 geometryFlipped 属性为 YES 将是组简单的解决方式。OS X 10.8 和之后的系统中,AppKit 为你管理这个属性。对于 iOS 应用,最好不要使用这个属性。


所有的坐标值,无论是坐标点还是 unit 坐标都是浮点数。浮点数的使用可以指出可能介于正常的坐标值之间位置的精确值,而且还很方便,尤其是打印时或者绘制一个点代表多个像素的 Retina 显示时。浮点数的使用可以让你忽略对设备展示的依赖,仅仅需要指出你想要的精度值即可。

Anchor Points Affect Geometric Manipulations

你可以用 layer 的 achorPoint 属性来操控 layer 的集合形状。最值得注意的是锚点的改变会影响到 position 或 transform 属性的操作。position 属性总是依赖于layer 的锚点来明确,而任何你应用的变形也取决于相关的锚点。

图 1-5 说明了锚点从默认值改变为另一值时对 layer 的position 属性的影响,尽管 layer 没有在父层的 bounds 中并没有移动,从 layer 的中心移动锚点纸 layer 的 bounds 原点改变了 position 属性值。

图 1-5 How the anchor point affects the layer's position property

图 1-6 展示了原点的变化怎样影响应用在 layer 上的变形。当你在 layer 上应用旋转变形时,旋转是以锚点为中心。因为锚点默认被设置在 layer 的中间,此时可以产生你所期望的旋转形态,然而更改了毛点后,旋转的结果就不同了。

图 1-6 How the anchor point affects layer transformations

Layers Can Be Manipulated in Three Dimensions

每一个 layer 都有两个 transform 矩阵,你可以用来操控 layer 和它的内容。CALayer 的 transform 属性指出了你想应用在 layer 和它内嵌的子 layer形态。一般在你想修改 layer 自身时用这个属性。例如,你可以用此属性等比例缩放或旋转 layer 或 改变 暂时性地改变 position。sublayerTransform 属性定义了额外的变形,仅仅用在子 layer 中,常常用来往图形内容中单独添加可见视觉现象。

Transform 依靠数值矩阵的多个坐标值获得新的坐标集,此做标记代表原点变形后的版本。Core Animation 的值可以在三维中指出,所以每个坐标点有四个值,可以用 4x4的矩阵标示,如图 1-7 。图形中的 transform 对应 CATransform3D 类型。幸运的是你不用直接修改这个结构的字段来形成一个变形,Core Animation提供综合的方法集来创建 scale, translation和 rotation 矩阵,而且可以做矩阵比较。另外关于方法操作变形,Core Animation 用键值对的编码,支持直接用键值改变变形。你可以修改的键列表,详见 CATransform3D Key Paths

图 1-7 Converting a coordinate using matrix math

图 1-8 显示了一般变形中你会用到的矩阵配置。身份坐标值和其他坐标值的乘积返回的还是同样的坐标。其他的变形中坐标怎么被修改完全依赖矩阵元素的改变。例如,沿着X轴移动,你只需要为矩阵中的 tx 元素提供一个非零的数值,把 ty 和 tz 的值设为 0 即可。再比如旋转,你提供旋转角度的正弦、余弦值就行了。

图 1-8 Matrix configurations for common transformations

你可以创建和操作变形的相关方法,详见 Core Animation Function Reference

Layer Trees Reflect Different Aspects of the Animation State

一个 app 在使用 Core Animation 时有三个 layer 对象集。当 app 的内容在屏幕显示时每一 layer 对象集都扮演着不同的角色:

  • layer 模型树对象(或简称 layer 树)是你的 app 中交互最多的。其中的对象属于模型对象,用来储存动画相关的目标值。在你改变一个 layer 的属性时使用的就是这些对象。
  • presentation 树对象包含的是动画在执行中的状态值。其中的目标值代表的时当前动画在屏幕上呈现的当前值。你可以用这些对象读取当前动画值但是别修改。
  • render 树对象是 Core Animation 私有的,专门变现实际的动画。

每一个 layer 对象集在 app 中都是像视图一样以层次结构组织起来的。事实上在 app 的所有视图中,有效的 layer 在初始时是何视图的层次机构相匹配的。app 可以根据需求添加额外的 layer 对象到已有的 layer 层次中(layer 和 view 是不相关的),当对一个视图的最顶层不需要的内容就行性能优化时你可能会用到。图 1-9 展示了 layer 在一个简单 ios app 中的分解。示例中的 window 包含内容视图,内容视图包含一个 button 视图和两个单独的 layer 对象,每一个视图都有相关的 layer 对象,它们一起构成了 layer 的层次。

图 1-9 Layers associated with a window

如图 1-10,对于每一个 layer 树的对象,presentation 和 render 树对象是一一对应的。正如之前提到的,app 主要用 layer 树中的对象工作,有时会访问 presentation 树的对象。使用 layer 树的对象 presentationLayer 可以获得 presentation 树相关的对象。当动画进行时你可能会想获得属性的相关值,访问这个对象即可。

图 1-10 The layer trees for a window


重要提示:你只能在动画进行时访问 presentation 树的对象。在动画的进行过程中,presentation 树包含 layer 显示在屏幕上那一瞬间的各种值。这种行为和 layer 树相比是完全不同的,layer 树总是反应你代码的最终值,也就是动画最终的状态。


The Relationship Between Layers and Views

layer 并不是你 app 中视图的替代,你不能在一个单独的 layer 对象上构建一个可视界面。Layer 可以为你的视图提供基础设施。最明确的一点就是 layer 可以提高视图内容的绘制和动画的效率和框架率。但是还有一些其它的 layer 完不成,不能处理事件,绘制内容,成为响应链的一环,或者其它的一些事情。因此每一个 app 必须要有一个或多个视图来处理这类的交互。

在 iOS 中,每一个视图都是构建在一个相关的 layer 对象之上,在 OS X 中需要你手动决定哪个视图应该有 layer。在 OS X v10.8 及之后的版本中,为所有视图添加 layer 是比较合情理的,但是这也不是必须的,你仍然可以为那些不合理的视图内容禁用 layer。Layer 的使用确实会增加 app 的内存使用,但是它的使用利大于弊,所以在禁用 layer 时最好测试一下 app 的性能。

当你开启 layer 对一个视图的支持时,此视图就被作为一个 layer-backed 视图。在 layer-backed 视图中,系统负责创建视图之下的 layer,保持视图和 layer 之间的同步。所有的 iOS 视图都是 layer-backed 视图,OS X 大部分视图是。但是在 OS X 中你可以创建一个 layer-hosting 视图,一个你为其提供 layer 对象的视图。关于 layer-hosting 视图,AppKit 提供了 layer 方便的管理方式,不用在视图的响应变换时修改它。


注意:对于 layer-backed 视图,强烈建议你尽可能的管理视图而不是它的 layer。在 iOS 中,视图仅仅是对 layer object的封装,因此你对 layer 的操作一般都会正常运行。但是无论是 ios 还是 os x,都出现过用修改 layer 代替视图修改时发生错误的状况。本文档会尽可能的指出这些误区。


尽管 layer 和视图有关联,你仍然可以创建一个和视图不相关的 layer 对象。你可以把这个单独的 layer 对象嵌入到其他的 layer 对象中,然后把他们和一个视图相关联。在性能优化时一般会采用此方法。例如,如果你想在多个地方使用同一张图片,你可以只加载一次这张图片,把它和几个单独的 layer 对象相关联,然后把他们加入到 layer 树中,那么每个 layer 都会引用它,而不是重新 copy 到内存中。

怎么在 app 中为视图启用 layer,详见 Enabling Core Animation Support in Your App。关于怎么创建 layer 对象层和其他的提示,详见 Building a Layer Hierarchy

posted @ 2015-01-17 15:00  1oo1  阅读(381)  评论(0编辑  收藏  举报