图层不但给自己提供可视化的内容和管理动画,而且充当了其他图层的容器类,构建图层层次结构。

本章介绍了图层层次结构,以及如何操纵该图层层次结构。

 

1.1 什么是图层树的层次结构

图层树是核心动画里面类似Cocoa视图的层次结构。比如一个NSView或者UIView的实例拥有父视图(superview)和子视图(subview),一个核心动画的图层拥有父图层(suplayer)和子图层(sublayer)。图层树和视图结构一样提供了很多便利:

  • 复杂的接口可以由简单的图层来组合,避免了硕大和复杂的继承化子类。图层非常合适于这种堆叠方式来合成复杂的功能。
  • 每个图层定义了一个基于其父图层的坐标系的坐标系。当一个图层变换的时候,它的子图层同样变换。
  • 一个动态的图层树,可以在程序运行的时候重新设置。图层可以创建并添加为一个图层的第一个子图层,然后从其他图层的图层树上面删除。

 

1.2 在视图里面显示图层

核心动画不提供在一个窗口(window)实际显示图层的手段,它们必须通过视图来托管。当视图和图层一起的时候,视图为图层提供了底层的事件处理,而图层为视图提供了显示的内容。

iOS上面的视图系统直接建立在核心动画的图层上面。每个UIView的实例会自动的创建一个CALayer类的实例,然后把该实例赋值给视图的layer属性。你可以在需要的时候向视图的图层里面添加子图层。

在Mac OS X,您必须配置一个NSView的实例,通过这样一种方式才可以让它托管图层。为了显示图层树的根图层,你可以设置一个视图的图层和配置视图以便使用图层:

代码 1  向view中插入layer

// theView is an existing view in a window
// theRootLayer is the root layer of a layer tree

[theView setLayer: theRootLayer];
[theView setWantsLayer:YES];

  

1.3 从图层结构里面添加和删除图层

简单的实例化一个图层并不意味已经把它插入了一个图层树。而是通过以下表1的方法来实现从图层树里面添加、插入、替换和删除图层。

表 1  图层树的管理函数

Method

Result

addSublayer:

Appends the layer to the receiver’s sublayers array.

insertSublayer:atIndex:

Inserts the layer as a sublayer of the receiver at the specified index.

insertSublayer:below:

Inserts the layer into the receiver’s sublayers array, below the specified sublayer.

insertSublayer:above:

Inserts the layer into the receiver’s sublayers array, above the specified sublayer.

removeFromSuperlayer

Removes the receiver from the sublayers array or mask property of the receiver’s superlayer.

replaceSublayer:with:

Replaces the layer in the receiver’s sublayers array with the specified new layer.

 

你也可以通过使用一个图层的数组来设置图层的子图层,甚至可以扩展设置父图层的sublayers属性。当把图层的sublayers属性设置了一个图层的数组值的时候,你必须保证数组里面每个图层的父图层已经被设置为nil。

默认情况下从一个可视化图层树里面插入和删除图层将会触发动画。当把一个图层添加为子图层的时候,将会触发父图层返回标识符为kCAOnOrderIn动画。当从图层的子图层里面删除一个图层的时候,将会触发父图层返回一个标识符为kCAOnOrderOut的动画。当替换图层的子图层里面的一个图层的时候,将会触发父图层返回一个标识符为KCATransition的动画。当你操作图层树的时候,你可以禁用动画或者改变使用任何标识符的动画。

 

1.4 图层的位置调整和大小改变

图层创建以后,你可以通过改变图层的几何属性:frame、bounds、position、anchorPoint和zPosition来编程式移动和改变图层大小。

如果一个图层的属性needsDisplayOnBoundsChange被设置为YES的时候,当图层的bounds属性改变的时候,图层的内容将会被重新缓存起来。默认情况下图层的needsDisplayOnBoundsChange属性值为NO。

默认情况下,设置图层的属性frame、bounds、position、anchorPoint和zPosition属性将会导致图层动画显示新值。

 

1.4.1 自动调整图层大小

CALayer提供了一个机制,在父图层被移动或者改变大小的时候,子图层可以自动的跟着移动和调整大小。在很多情况下简单的配置一个图层的自动调整掩码(autoresizing  mask)可以适当的适应程序的行为。

一个图层的自动调整掩码可以通过指定CAAutoresizingMask的常量结合或运算(OR)所得的结果赋值给图层的autoresizingMask属性值。表2列举了掩码常量和这些掩码如何影响图层的大小调整行为。

表 2  自动缩放掩码及其解释

Autoresizing Mask

Description

kCALayerHeightSizable

如果设置了,则layer的高度按比例随父layer的高度变化。

kCALayerWidthSizable

如果设置了,则layer的宽度按比例随父layer的宽度变化。

kCALayerMinXMargin

如果设置了,则layer的左边距按比例随父layer的宽度变化。如果未设置,则layer的左边距保持原来相对父layer的位置。

kCALayerMaxXMargin

如果设置了,则layer的右边距按比例随父layer的宽度变化。如果未设置,则layer的右边距保持原来相对父layer的位置。

kCALayerMaxYMargin

如果设置了,则layer的上边距按比例随父layer的宽度变化。如果未设置,则layer的上边距保持原来相对父layer的位置。

kCALayerMinYMargin

如果设置了,则layer的下边距按比例随父layer的宽度变化。如果未设置,则layer的下边距保持原来相对父layer的位置。

 

例如,为了把保持图层位于它父图层的相对左下角位置,你可以使用kCALayerMaxXMargin | kCALayerMaxYMargin。当沿着一个轴具有多个方向被设置为适应可变的时候,那么调整大小的尺寸为使其均匀分布的值。图1提供了一个常量值的位置的图形表示。

图 1  Layer的自缩放掩码常量

 

 

当这些常量里面的任何一个被省略的时候,图层的布局在这个方向上值是固定的。当一个常量包含在图层的自动调整掩码里面的时候,该方向上的图层的布局值是适应可变的。

CALayer的子类可以重写函数resizeSublayersWithOldSize:和resizeWithOldSuperlayerSize:来定制化的自动调整图层大小的行为。图层的函数resizeSublayersWithOldSize:将会在bounds属性被修改的时候自动的触发执行,同时发送一个消息resizeWithOldSuperlayerSize:给图层的每个子图层。图层的每个子图层根据自动调整掩码的属性来比较就的边界值和新的边界值来调整它的位置和大小。

 

1.5 裁剪子图层

在Cocoa的视图里面,当子视图超出父视图的边界的时候,视图将会被裁剪以适应父视图的大小。图层去掉了这个限制,允许子层全部显示,无论自己相对于父层位置如何。图层的masksToBounds属性决定了是否子图层是否相对父图层裁剪。该属性masksToBounds的默认值为NO,即防止子图层被相对于父图层裁剪。表2显示了当设置图层的masksToBounds属性导致的结果,和它如何影响layerB和layerC的显示。 

图 2  masksToBounds 属性的实例值

 

评论模块尚未加载