1. The Layer Tree
Ogres have layers. Onions have layers. You get it? We both have layers.
——Shrek
Core Animation 的名字很容易引起误解,让大家都认为它的主要目的是实现动画的,实际上动画只是 Core Animation 框架的功能之一,Core Animation 框架最开始的名字是 Layer kit。
Core Animation 是一个组装引擎(compositing engine),它的工作是尽快地将屏幕上的各块独立的内容组合起来用来展示。这些由各独立内容组合起来的层级结构就是 layer tree。
Layers 和 Views 的关系:表面上看,UIView 和 CAlayer 一样,都是方形的,可以通过叠加组成层级关系,可以展示图片、文字、颜色等内容,可以管理子层级的位置,可以执行动画;实际上,对于 UIView,关于渲染(rendering)、布局(layout)、动画(animation)的这些工作,都不是由 view 自己处理的,而是 layer 处理的;唯一一个 CALyer 不能处理而由 UIView 自己处理的任务是触摸事件等用户交互。
每一个 UIView 都有一个叫做 layer 的 CALayer 属性。也就是常说的 backing layer,view 的职责就是创建和管理这个 layer,来保证当添加或移除 subviews 时,layer 层也在添加或移除相应的 layer。
实际上,UIView 在屏幕上的展示和动画都是由 backing layers 来实现的,UIView 只是一个 CALayer 的简单的封装,只提供一些像触摸事件响应等 iOS 独有的功能,以及一些 Core Animation 底层功能的高级接口。
为什么 iOS 有这两个分别基于 UIView 和 CALayer 的并列层级?为什么不是一个能够管理所有任务的层级?原因就在于分清职责,避免代码重复。
在 iOS 和 Mac OS 上,对事件(event)和用户交互(user interaction)的处理方式是不同的;处理手势操作和处理鼠标键盘的机制是不同的,所以 iOS 中有 UIKit 和 UIView,而 Mac OS 有 AppKit 和 NSView,它们的功能很相似,但是实现方式却有显著的差异。
渲染(rendering)、布局(layout)、动画(animation)这些功能在iPhone、iPad等触屏设备上和在 MacBook 等非触屏设备上是一样的。通过将这些功能相关的逻辑单独分离出来成 Core Animation 框架,Apple 就能够在 iOS 和 Mac OS 之间共享这些代码了,这对于Apple 自家的 OS 开发团队以及那些要开发能在两个平台都能运行的 app 的第三方开发者来说,事情变得更简单了。
事实上,除了 view hierarchy 和 layer tree 这两个层级之外,还有 presentation tree 和 render tree 另外两个层级,这四个层级,每个层级都扮演着不同的角色。
如果 CALayer 不过是 UIView 内部的具体实现而已,那我们为什么还要去了解它?从某种程度上来讲,我们确实不需要接触 CALayer 就可以直接通过 UIView 得高级接口来绘制图形,实现动画。但是,使用简单同时也意味着失去了灵活性,如果你想实现一些与接口本身所提供的功能不一样,或者要使用一些 Apple 没有在 UIView 中暴露出来的接口时,你就需要倒腾一下偏底层的 Core Animation 了。
那么,有什么事情是 CALayer 能做,而 UIView 做不了的呢?
绘制带阴影、圆角、边框的图形(Drop shadows, rounded corners, and colored borders)
3D 变换(3D transforms and positioning)
不是方形的图形(Nonrectangular bounds)
视图内容上加一些遮罩(Alpha masking of content)
多步骤动画,非线性动画(Multistep, nonlinear animations)
大多数情况下,相比直接操作独立的 CALayer 对象,用带有 backing layer 的 UIView 对象来绘制图形,往往更简单,因为 UIVIew 有一些像 autoresizing、autolayout、event handling 等 CALayer 没有的功能。
-
只有极个别情况下,你应该使用独立的 CALayer,而不是带有 backing layer 的 UIView:
- You might be writing cross-platform code that will also need to work on a Mac.
- You might be working with multiple CALayer subclasses and have no desire to create new UIView subclasses to hostthem all.
- You might be doing such performance-critical work that even the negligible overheadof maintaining the extra UIView object makes a measurable difference (although inthat case, you’ll probably want to use something like OpenGL for your drawinganyway).