标签:
第四章 图层树的层次结构
图层不但给自己提供可视化的内容和管理动画,而且充当了其他图层的容器类,
构建图层层次结构。
本章介绍了图层层次结构,以及如何操纵该图层层次结构。
4.1 什么是图层树的层次结构
图层树是核心动画里面类似 Cocoa 视图的层次结构。比如一个 NSView 或者UIView 的实例拥有父视图(superview)和子视图(subview),一个核心动画的图层拥有父图层(suplayer)和子图层(sublayer)。图层树和视图结构一样提供了很多便利:
复杂的接口可以由简单的图层来组合,避免了硕大和复杂的继承化子类。图层非常合适于这种堆叠方式来合成复杂的功能。
每个图层定义了一个基于其父图层的坐标系的坐标系。当一个图层变换的时候,它的子图层同样变换。
一个动态的图层树,可以在程序运行的时候重新设置。图层可以创建并添加为一个图层的第一个子图层,然后从其他图层的图层树上面删除。
4.2 在视图里面显示图层
核心动画不提供在一个窗口(window)实际显示图层的手段,它们必须通过视图来托管。当视图和图层一起的时候,视图为图层提供了底层的事件处理,而图层为视图提供了显示的内容。
iOS 上面的视图系统直接建立在核心动画的图层上面。每个 UIView 的实例会自动的创建一个 CALayer 类的实例,然后把该实例赋值给视图的 layer 属性。你可以在需要的时候向视图的图层里面添加子图层。
在 Mac OS X,您必须配置一个 NSView 的实例,通过这样一种方式才可以让它托管图层。为了显示图层树的根图层,你可以设置一个视图的图层和配置视图以便使用图层。具体如表 2.
// theView is an existing view in a window
|
// theRootLayer is the root layer of a layer tree
|
[theView setLayer: theRootLayer];
|
4.3 从图层结构里面添加和删除图层
简单的实例化一个图层并不意味已经把它插入了一个图层树。而是通过以下表 1的方法来实现从图层树里面添加、插入、替换和删除图层。
Table 1 Layer-tree management methods.
// theView is an existing view in a window
|
// theRootLayer is the root layer of a layer tree
|
[theView setLayer: theRootLayer];
|
[theView setWantsLayer:YES];
|
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’ssuperlayer. |
replaceSublayer:with:
|
Replaces the layer in the receiver’s sublayers array with the specified new layer. |
你也可以通过使用一个图层的数组来设置图层的子图层,甚至可以扩展设置父图层的 sublayers 属性。当把图层的 sublayers 属性设置了一个图层的数组值的时候,你必须保证数组里面每个图层的父图层已经被设置为 nil。
默认情况下从一个可视化图层树里面插入和删除图层将会触发动画。当把一个图层添加为子图层的时候,将会触发父图层返回标识符为 kCAOnOrderIn 动画。当从图层的子图层里面删除一个图层的时候,将会触发父图层返回一个标识符为kCAOnOrderOut 的动画。当替换图层的子图层里面的一个图层的时候,将会触发父图层返回一个标识符为 KCATransition 的动画。当你操作图层树的时候,你可以禁用动画或者改变使用任何标识符的动画。
2011-11-14|?2011YouMiMobileCo.Ltd.AllRightsReserved.[18]
Core Animation Programming Guide
4.4 图层的位置调整和大小改变
图层创建以后,你可以通过改变图层的几何属性:frame、bounds、position、anchorPoint 和 zPosition 来编程式移动和改变图层大小。
如果一个图层的属性 needsDisplayOnBoundsChange 被设置为 YES 的时候,当图层的 bounds 属性改变的时候,图层的内容将会被重新缓存起来。默认情况下图层的needsDisplayOnBoundsChange 属性值为 NO。
默认情况下,设置图层的属性 frame、bounds、position、anchorPoint 和 zPosition属性将会导致图层动画显示新值。
4.4.1 自动调整图层大小
CALayer 提供了一个机制,在父图层被移动或者改变大小的时候,子图层可以自动的跟着移动和调整大小。在很多情况下简单的配置一个图层的自动调整掩码(autoresizing mask)可以适当的适应程序的行为。
一个图层的自动调整掩码可以通过指定 CAAutoresizingMask 的常量结合或运算(OR)所得的结果赋值给图层的 autoresizingMask 属性值。表 2 列举了掩码常量和这些掩码如何影响图层的大小调整行为。
Table 2 Autoresizing mask values and descriptions
Autoresizing Mask |
Description |
kCALayerHeightSizable
|
If set, the layer‘s height changes proportionally to the change in the superlayer‘s height.Otherwise, the layer‘s height does not change relative to the superlayer‘s height. |
kCALayerWidthSizable
|
If set, the layer‘s width changes proportionally to the change in the superlayer‘s width.Otherwise, the layer‘s width does not change relative to the superlayer‘s width. |
kCALayerMinXMargin
|
If set, the layer‘s left edge is repositioned proportionally to the change in the superlayer‘swidth. Otherwise, the layer‘s left edge remains in the same position relative to thesuperlayer‘s left edge. |
kCALayerMaxXMargin
|
If set, the layer‘s right edge is repositioned proportionally to the change in the superlayer‘swidth. Otherwise, the layer‘s right edge remains in the same position relative to thesuperlayer. |
kCALayerMaxYMargin
|
If set, the layer‘s top edge is repositioned proportionally to the change in the superlayer‘sheight. Otherwise, the layer‘s top edge remains in the same position relative to thesuperlayer. |
kCALayerMinYMargin
|
If set, the layer‘s bottom edge is repositioned proportional to the change in the superlayer‘sheight. Otherwise, the layer‘s bottom edge remains in the same position relative to thesuperlayer. |
2011-11-14|?2011YouMiMobileCo.Ltd.AllRightsReserved.[19]
Core Animation Programming Guide
例如,为了把保持图层位于它父图层的相对左下角位置,你可以使用
kCALayerMaxXMargin | kCALayerMaxYMargin。当沿着一个轴具有多个方向被设置为适应可变的时候,那么调整大小的尺寸为使其均匀分布的值。图 1 提供了一个常量值的位置的图形表示。
Figure 1 Layer autoresizing mask constants
当这些常量里面的任何一个被省略的时候,图层的布局在这个方向上值是固定的。当一个常量包含在图层的自动调整掩码里面的时候,该方向上的图层的布局值是适应可变的。
CALayer 的 子 类 可 以 重 写 函 数 resizeSublayersWithOldSize: 和resizeWithOldSuperlayerSize:来定制化的自动调整图层大小的行为。图层的函数resizeSublayersWithOldSize:将会在 bounds 属性被修改的时候自动的触发执行,同时发送一个消息 resizeWithOldSuperlayerSize:给图层的每个子图层。图层的每个子图层根据自动调整掩码的属性来比较就的边界值和新的边界值来调整它的位置和大小。
4.5 裁剪子图层
在 Cocoa 的视图里面,当子视图超出父视图的边界的时候,视图将会被裁剪以适应父视图的大小。图层去掉了这个限制,允许子层全部显示,无论自己相对于父层位置如何。图层的 masksToBounds 属性决定了是否子图层是否相对父图层裁剪。该属性masksToBounds 的默认值为 NO,即防止子图层被相对于父图层裁剪。表 2 显示了当设置图层的 masksToBounds 属性导致的结果,和它如何影响 layerB 和 layerC 的显示。
2011-11-14|?2011YouMiMobileCo.Ltd.AllRightsReserved.[20]
Core Animation Programming Guide
Figure 2 Example Values of the masksToBounds property
2011-11-14|?2011YouMiMobileCo.Ltd.AllRightsReserved.[21]
Core Animation Programming Guide
第五章 提供图层内容
当我们使用 Cocoa 的视图的时候,我们必须继承 NSView 或者 UIView 并且重载函数 drawRect:来显示任何内容。但是 CALayer 实例可以直接使用,而无需继承子类。因为 CALayer 是一个键-值编码兼容的容器类,你可以在实例里面存储任意值,所以子类实例化完全可以避免。
5.1 给CALayer提供内容
你可以通过以下任何一种方法指定
CALayer
实例的内容:
使用包含图片内容的
CGImageRef
来显式的设置图层的
contents
的属性。
指定一个委托,它提供或者重绘内容。
继承
CALayer
类重载显示的函数。
5.1.1 设置contents属性
图层的图片内容可以通过指定 contents 属性的值为 CGImageRef。当图层被创建的时候或者在任何其他时候,这个操作可以在其他实体上面完成(如表 3 所示)。
Listing 1 Setting a layer’s contents property
CALayer *theLayer;
|
// create the layer and set the bounds and position
|
theLayer=[CALayer layer];
|
theLayer.position=CGPointMake(50.0f,50.0f);
|
theLayer.bounds=CGRectMake(0.0f,0.0f,100.0f,100.0f); |
// set the contents property to a CGImageRef
|
// specified by theImage (loaded elsewhere)
|
theLayer.contents=theImage;
|
5.1.2 通过委托提供内容你可以绘制图层的内容,或更好的封装图层的内容图片,通过创建一个委托类实
2011-11-14|?2011YouMiMobileCo.Ltd.AllRightsReserved.[22]
Core Animation Programming Guide
现下列方法之一:
displayLayer:或 drawLayer:inContext:
实现委托重绘的方法并不意味会自动的触发图层使用实现的方法来重绘内容。而是你要显式的告诉一个图层实例来重新缓存内容,通过发送以下任何一个方法setNeedsDisplay 或 者 setNeedsDisplayInRect: 的 消 息 , 或 者 把 图 层 的needsDisplayOnBoundsChange 属性值设置为 YES。
通过委托实现方法 displayLayer:可以根据特定的图层决定显示什么图片,还可以更加需要设置图层的 contents 属性值。下面的例子是“图层的坐标系”部分的,它实现 displayerLayer:方法根据 state 的值设置 theLayer 的 contents 属性。子类不需要存储state 的值,因为 CALayer 的实例是一个键-值编码容器。
Listing 2 Example implementation of the delegate method displayLayer:
- (void)displayLayer:(CALayer *)theLayer
|
{ |
// check the value of the layer‘s state key
|
if ([[theLayer valueForKey:@"state"] boolValue])
|
{ |
// display the yes image
|
theLayer.contents=[someHelperObject loadStateYesImage];
|
} |
else { |
// display the no image
|
theLayer.contents=[someHelperObject loadStateNoImage];
|
} |
} |
如果你必须重绘图层的内容,而不是通过加载图片,那你需要实现drawLayer:inContext:方法。通过委托可以决定哪些内容是需要的并使用CGContextRef 来重绘内容。
下面的例子是“指定图层的几何”部分内容,它实现了 drawLayer:inContext:方法使用 lineWidth 键值来重绘一个路径(path),返回 therLayer。
2011-11-14|?2011YouMiMobileCo.Ltd.AllRightsReserved.[23]
Core Animation Programming Guide
Listing 3 Example implementation of the delegate method drawLayer:inContext:
- (void)drawLayer:(CALayer *)theLayer
|
inContext:(CGContextRef)theContext
|
{ |
CGMutablePathRef thePath = CGPathCreateMutable();
|
CGPathMoveToPoint(thePath,NULL,15.0f,15.f);
|
CGPathAddCurveToPoint(thePath,
|
NULL, |
15.f,250.0f,
|
295.0f,250.0f,
|
295.0f,15.0f);
|
CGContextBeginPath(theContext);
|
CGContextAddPath(theContext, thePath );
|
CGContextSetLineWidth(theContext,
|
[[theLayer valueForKey:@"lineWidth"] floatValue]);
|
CGContextStrokePath(theContext);
|
// release the path
|
CFRelease(thePath);
|
} |
5.1.3 通过子类提供图层的内容
虽然通常情况不需要这样做,但是你仍可以继承 CALayer 直接重载重绘和显示方法。这个通常发生在你的图层需要定制行为而委托又无法满足需求的时候。
子类可以重载 CALayer 的显示方法,设置图层的内容为适当的图片。下面的例子是“变换图层的几何”部分的内容,它提供了和“图层的坐标系”例子相同的功能。不同的是子类定义 state 为实例的属性,而不是根据 CALayer 的键-值编码容器获取。
2011-11-14|?2011YouMiMobileCo.Ltd.AllRightsReserved.[24]
Core Animation Programming Guide
Listing 4 Example override of the CALayer display method
- (void)drawInContext:(CGContextRef)theContext
|
{ |
CGMutablePathRef thePath = CGPathCreateMutable();
|
CGPathMoveToPoint(thePath,NULL,15.0f,15.f);
|
CGPathAddCurveToPoint(thePath,
|
NULL, |
15.f,250.0f,
|
295.0f,250.0f,
|
295.0f,15.0f);
|
CGContextBeginPath(theContext);
|
CGContextAddPath(theContext, thePath );
|
CGContextSetLineWidth(theContext,
|
self.lineWidth);
|
CGContextSetStrokeColorWithColor(theContext,
|
self.lineColor);
|
CGContextStrokePath(theContext);
|
CFRelease(thePath);
|
} |
CALayer 子类可以通过重载 drawInContext:绘制图层的内容到一个图形上下文。下面的例子是“修改变换的数据结构”的内容,它和“指定图层的几何”里面实现委托的办法一样产生相同的图片内容。唯一的不同的是实现委托里面的 lineWidth 和lineColor 现在是子类实例的属性。
Listing 5 Example override of the CALayer drawInContext: method
- (void)drawInContext:(CGContextRef)theContext
|
{ |
CGMutablePathRef thePath = CGPathCreateMutable();
|
2011-11-14|?2011YouMiMobileCo.Ltd.AllRightsReserved.[25]
Core Animation Programming Guide
CGPathMoveToPoint(thePath,NULL,15.0f,15.f);
|
CGPathAddCurveToPoint(thePath,
|
NULL, |
15.f,250.0f,
|
295.0f,250.0f,
|
295.0f,15.0f);
|
CGContextBeginPath(theContext);
|
CGContextAddPath(theContext, thePath );
|
CGContextSetLineWidth(theContext,
|
self.lineWidth);
|
CGContextSetStrokeColorWithColor(theContext,
|
self.lineColor);
|
CGContextStrokePath(theContext);
|
CFRelease(thePath);
|
} |
继承 CALayer 并且实现其中的重绘方法并不意味重绘会自动发生。你必须显式的促使实例重新缓存其内容,可以通过发送以下任何一个方法 setNeedsDisplay 或setNeedsDisplayInRect:的消息,亦或者设置图层的 needsDisplaOnBoundsChange 属性为 YES。
5.2 修改图层内容的位置
CALayer 的属性 contentsGravity 允许你在图层的边界内容修改图层的 contents 图片的位置或者伸缩值。默认情况下,内容的图像完全填充层的边界,忽视自然的图像宽高比。
使用 contentsGravity 位置常量,你可以指定图片位于图层任何一个边界,比如位于图层的角落,或者图层边界的中心。然而当你使用位置常量的时候,contentsCenter属性会被忽略。表 1 列举了位置常量和他们相应的位置。
2011-11-14|?2011YouMiMobileCo.Ltd.AllRightsReserved.[26]
Core Animation Programming Guide
Table 1 Positioning constants for a layer’s contentsGravity property
Position constant Description |
kCAGravityTopLeft Positions the content image in the top left corner of the layer. |
kCAGravityTop
Positions the content image horizontally centered along the top edge of thelayer. |
kCAGravityTopRight Positions the content image in the top right corner of the layer. |
kCAGravityLeft Positions the content image vertically centered on the left edge of the layer. |
kCAGravityCenter Positions the content image at the center of the layer. |
kCAGravityRight Positions the content image vertically centered on the right edge of the layer. |
kCAGravityBottomLeft Positions the content image in the bottom left corner of the layer. |
kCAGravityBottom Positions the content image centered along the bottom edge of the layer. |
kCAGravityBottomRight Positions the content image in the top right corner of the layer. |
“图层的坐标系”标识了所支持的内容位置和他们相应的常量。Figure 1 Position constants for a layer’s contentsGravity property
通过设置 contentsGravity 属性为其他一个常量(如表 2 所示)。图层的内容图片可以被向上或者向下拉伸, 仅当使用其他任何一个调整大小的常量的时候,contentsCenter 属性才会对内容图片起作用。
2011-11-14|?2011YouMiMobileCo.Ltd.AllRightsReserved.[27]
Core Animation Programming Guide
Table2 ScalingConstantsForALayer’scontentsGravityProperty
Scaling constant |
Description |
kCAGravityResize
|
Resize the content image to completely fill the layer bounds,potentially ignoring the natural aspect of the content. This is thedefault. |
kCAGravityResizeAspect
|
Resize the content image to scale such that it is displayed as large aspossible within the layer bounds, yet still retains its natural aspect. |
kCAGravityResizeAspectFill
|
Resize the content image to scale such that it is displayed filling thelayer bounds, yet retaining its natural aspect. This may cause thecontent to extend outside the layer bounds. |
“变换图层的几何”演示了如何使用调整大小的模式来调整一个正方形图像的大小让其适应图层的方形边界。
Figure 2 Scaling constants for a layer’s contentsGravity property
注 意 : 使 用 任 何 常 量 kCAGravityResize 、 kCAGravityResizeAspect 和kCAGravityResizeAspectFill 和表 1 中的重心位置常量无关。图层的内容将会填充整个边界,所以使用这些常量无法改变图层内容的位置。
标签:
原文地址:http://blog.csdn.net/super_man_ww/article/details/51361356