iOS核心动画进阶选译(1)The layer tree

核心动画这个名字本身具有误导性。看到这个名字,大家很可能会认为这个框架(framework)的首要功能是动画,但事实上,动画只是这个框架的一个小的方面。这个框架之前的名字叫做Layer Kit。

核心动画是一个合成引擎,它的工作是尽可能快的将不同的可视化的内容合成到屏幕上。这个可视化内容是不同的层(layer),构成一个叫做层树(layer tree)的层次结构。

这个树结构是UIKit的基础材料。

在讨论动画之前,我们先要讨论核心动画的静态合成(static composing)和与布局相关的特性,让我们从层树开始入手吧。

层(layer)和视图(view)

如果你曾经为iOS或者Mac OS写过应用的话,那么你一定对视图(view)的概念很熟悉了。一个视图是一个矩形对象,用来显示内容(比如图像,文本,和视频)并且截获用户输入(比如鼠标的点击或者触摸屏幕)。视图可以嵌套,形成一个视图层次结构,每一个视图负责管理它子视图的位置。图1.1描绘了一个典型的视图层次结构。


图1.1 一个典型的iOS应用屏幕(左)和它所对应的视图层次结构(右)

在iOS中,视图都继承自一个基础类:UIView。UIView负责处理点击事件,提供对core graphics绘图的支持,处理仿射的的变换(比如旋转或改变比例),提供简单的动画支持(比如滑动或者渐变)。
你可能并不知道,以上这些功能很多都不是UIView直接处理的。渲染、布局、动画这些都是由核心动画的类型CALayer来控制的。

CALayer

CALayer类从概念上来看与UIView很类似。层(layer),和视图(view)一样,都是矩形的对象,都可以组成树形结构,可以包含可显示内容(比如图像、文本或者背景颜色),可以控制子层(sublayer)的位置。层具有与动画和变形相关的属性和方法。层与视图最大的不同就是层不负责用户交互。
CALayer不知道反应链的存在,所以也就不能对事件作出反应。但是层却有一些方法来帮助我们判断一个触摸事件是否发生在层的区域内(该内容会在第三章详细讨论)。

并行的层次结构

每一个UIView都有一个叫做layer的属性,它是一个类型为CAlayer的对象。这个对象被称为支撑层。视图负责创建和管理它的支撑层,保证当有其它视图成为其子视图时,子视图的支撑层成为其支撑层的子层,当子视图移走之后,子视图的支撑层也从其支撑层移走(图1.2)。

图1.2 层的树形结构(左)对应这视图的树形结构(右)
事实上,你在屏幕上看到的全部的内容和动画都是由支撑层来负责处理的。视图只是一个包装,提供一些iOS特有的功能,比如触摸事件的处理,并且为CALayer的某些功能封装了高级接口。
为什么iOS要搞出两个并行的树形结构呢?一个树形结构难道不能处理全部的事情吗?这样做的原因是要划分清楚责任,避免重复的代码。事件处理和用户交互在iOS和Mac OS上有很大的不同,为触摸屏而生的用户交互方式和为鼠标键盘而生的用户交互方式具有本质上的不同,这也解释了为什么iOS用UIKit和UIView,而Mac OS用AppKit和NSView。从功能上来看他们很类似,但是在实现上却大相径庭。
相反,绘制,布局以及动画,对无论是基于触摸操作的iPhone和Ipad,或者是传统的笔记本电脑与台式机都适用。通过把这部分的逻辑抽取出来,形成核心动画框架,这部分代码就可以在iOS和Mac OS中都能使用了,如果开发者需要为这两个平台都开发应用时,事情就变得相对简单了。
实际上,树形结构并不是仅仅有2个,而是有4个,每一个都有不同的作用。除了我们已经提到过的视图树形结构和层树形结构,还有一个表现树和渲染树,分别会在第七章和第十二章里讨论。

层的功能

如果层只是视图某些功能的内部实现类,那我们为什么还要去了解它?苹果提供了简单好用的UIView,我们就真的没有必要了解核心动画的细节了吗?
在某种程度上来讲的确是这样的。对于一些简单地任务,我们无需借助CALayer。因为UIView已经将CALayer的一些基本功能封装好了,我们可以间接的使用。但是这样会丧失灵活性。如果你要做的超出了UIView所能提供的,或者是你想用一些UIView并没有开放给我们的特性,你就别无选择,只能通过核心动画框架来寻求解决办法了。
我们已经知道CALayer不能处理触摸事件,而UIView可以,那么有什么是UIView不能做而CALayer能做的呢?以下是CALayer的一些特性,但是UIView却没有暴露出来:
阴影,圆角和彩色边框
三维空间变形和移动
非矩形范围
半透明遮盖
多步骤,非线性动画
接下来的章节会详细讨论以上内容,但是现在我们先来看一下在应用中如何利用CALAyer。

使用CALayer

让我们新建一个工程,熟悉一下CALayer的相关属性。在Xcode中,通过Single View Application模板新建一个iOS工程。在屏幕的中间创建一个小一点的View(大约200*200点),你可以通过代码创建,也可以在Interface Builder中创建,确保在view controller中有一个指向这个小view得属性,方便我们迅速找到它。我给他起个名字,叫做layerView。

运行这个工程,你会看到一个白色正方形出现在灰色的屏幕当中(图1.3)。如果你看到的不是这样的话,改变window或者父view的背景色。


图1.3 灰色背景上的白色UIView


这没什么令人激动的地方,让我们来添加点明快的色彩。我们在白色的方块中再添加一个蓝色的小方块。

要实现这样的效果,我们完全可以再新建一个更小的UIView,然后添加作为白色view的子view,但是这样做就不会接触的layer了。相反的,我们这里创建一个CALayer的对象,并将其添加到白色view的支撑层当中,作为支撑层的子层。首选,我们需要把所需要的框架添加到工程当中,这里我们需要添加QuartzCore Framework (图1.4),然后在view controller的.m文件中import <QuartzCore/QuartzCore.h> 。


图1.4 在工程中添加QuartzCore Framework

导入之后,我们就可以在代码中使用CALayer和它所包含的属性与方法了。在代码1.1中,我们创建了一个CALayer对象,然后将其背景颜色设置为蓝色,再然后,把它添加到layerView的支撑层中,作为子layer(图1.5)。

CALayer的backgroundColor的数据类型是CGColorRef,并不像UIView的backgroundColor属性的数据类型那样是UIColor。如果你愿意的话,你可以用core graphics中的方法来创建一个CGColorRef,但是我们也可以用UIColor的一个叫做CGColor的属性来获得CGColorRef,这样做你就不必手动释放颜色了。


代码1.1 给view添加蓝色子layer

#import "ViewController.h"
#import <QuartzCore/QuartzCore.h>
@interface ViewController ()
@property (nonatomic, weak) IBOutlet UIView *layerView;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
//create sublayer
CALayer *blueLayer = [CALayer layer];
blueLayer.frame = CGRectMake(50.0f, 50.0f, 100.0f, 100.0f);
 blueLayer.backgroundColor = [UIColor blueColor].CGColor;
//add it to our view
[self.layerView.layer addSublayer:blueLayer]; }
@end



图1.5 白色的view中添加了一个蓝色的layer

一个view只能有一个支撑层(由view自动创建),但是却可以任意给支撑层添加子层,就像我们在代码1.1中做的那样。大多数情况我们都无需创建子层,仅仅操作view和它的支撑层就能满足很大一部分工作。

这样做的好处是你不仅可以充分利用CALayer提供给我们的特性,同时还可以利用UIView提供的高级的接口方法(比如自动调整大小,自动布局,事件处理)。

但是,下列情况中,你将不得不使用CALayer而不是UIView:

你的代码同时也要运行在Mac OS上

你将用到一些CALayer的子类(第六章详细介绍)

你的代码对性能要求很高,UIView所带来的额外开销是不可忍受的(如果是这样的话,你可能会考虑使用OpenGL)


以上这些情况并不是很常见。使用UIView会比使用CAlayer更方便。

总结

本章介绍了层及其树形结构,它位于UIView树形结构之下,构成了iOS应用的显示界面。本章中,我们实验性的创建了一个CALayer的对象并加入了层的树形结构之中。下一章,我们将介绍位于CALayer之下的image及其相关的属性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值