iOS 图层树 一
1.1图层与视图
如果你曾经在iOS或者Mac OS平台上写过应用程序,你可能会对视图的概念比较熟悉。一个视图就是在屏幕上显示的一个矩形块(比如图片,文字或者视频),它能够拦截类似于鼠标点击或者触摸手势等用户输入。视图在层级关系中可以互相嵌套,一个视图可以管理它的所有子视图的位置。图1.1显示了一种典型的视图层级关系
图1.1 一种典型的iOS屏幕(左边)和形成视图的层级关系(右边)
在iOS当中,所有的视图都从一个叫做UIVIew
的基类派生而来,UIView
可以处理触摸事件,可以支持基于Core Graphics绘图,可以做仿射变换(例如旋转或者缩放),或者简单的类似于滑动或者渐变的动画。
CALayer
CALayer
类在概念上和UIView
类似,同样也是一些被层级关系树管理的矩形块,同样也可以包含一些内容(像图片,文本或者背景色),管理子图层的位置。它们有一些方法和属性用来做动画和变换。和UIView
最大的不同是CALayer
不处理用户的交互。
CALayer
并不清楚具体的响应链(iOS通过视图层级关系用来传送触摸事件的机制),于是它并不能够响应事件,即使它提供了一些方法来判断是否一个触点在图层的范围之内(具体见第三章,“图层的几何学”)
平行的层级关系
每一个UIview
都有一个CALayer
实例的图层属性,也就是所谓的backing layer,视图的职责就是创建并管理这个图层,以确保当子视图在层级关系中添加或者被移除的时候,他们关联的图层也同样对应在层级关系树当中有相同的操作(见图1.2)。 图1.2 图层的树状结构(左边)以及对应的视图层级(右边)
实际上这些背后关联的图层才是真正用来在屏幕上显示和做动画,UIView
仅仅是对它的一个封装,提供了一些iOS类似于处理触摸的具体功能,以及Core Animation底层方法的高级接口。
但是为什么iOS要基于UIView
和CALayer
提供两个平行的层级关系呢?为什么不用一个简单的层级来处理所有事情呢?原因在于要做职责分离,这样也能避免很多重复代码。在iOS和Mac OS两个平台上,事件和用户交互有很多地方的不同,基于多点触控的用户界面和基于鼠标键盘有着本质的区别,这就是为什么iOS有UIKit和UIView
,但是Mac OS有AppKit和NSView
的原因。他们功能上很相似,但是在实现上有着显著的区别。
绘图,布局和动画,相比之下就是类似Mac笔记本和桌面系列一样应用于iPhone和iPad触屏的概念。把这种功能的逻辑分开并应用到独立的Core Animation框架,苹果就能够在iOS和Mac OS之间共享代码,使得对苹果自己的OS开发团队和第三方开发者去开发两个平台的应用更加便捷。
实际上,这里并不是两个层级关系,而是四个,每一个都扮演不同的角色,除了视图层级和图层树之外,还存在呈现树和渲染树,将在第七章“隐式动画”和第十二章“性能调优”分别讨论。
1.2图层的能力
如果说CALayer
是UIView
内部实现细节,那我们为什么要全面地了解它呢?苹果当然为我们提供了优美简洁的UIView
接口,那么我们是否就没必要直接去处理Core Animation的细节了呢?
某种意义上说的确是这样,对一些简单的需求来说,我们确实没必要处理CALayer
,因为苹果已经通过UIView
的高级API间接地使得动画变得很简单。
但是这种简单会不可避免地带来一些灵活上的缺陷。如果你略微想在底层做一些改变,或者使用一些苹果没有在UIView
上实现的接口功能,这时除了介入Core Animation底层之外别无选择。
我们已经证实了图层不能像视图那样处理触摸事件,那么他能做哪些视图不能做的呢?这里有一些UIView
没有暴露出来的CALayer的功能:
- 阴影,圆角,带颜色的边框
- 3D变换
- 非矩形范围
- 透明遮罩
- 多级非线性动画
我们将会在后续章节中探索这些功能,首先我们要关注一下在应用程序当中CALayer
是怎样被利用起来的。