CoreAnimation编程指南(九)图层布局

NSView提供了经典的“stuts and springs”模式,用于视图调整大小的时候把关联到它父图层的视图重新调整位置。图层支持该模式,而且Mac OS X上面的核心动画提供了一个更通用的布局管理器机制,允许开发者自己写他们自己的布局管理器。可以为图层定制一个布局管理器(它通常实现CALayoutManager协议),负责给图层的子图层提供布局功能。

本章介绍了约束布局管理器和如何配置一系列约束条件。

iOS 注意:iOS的CALayer类仅提供“stuts and springs”模式,不提供定制的布局管理器。然而如果你想人工修改关联到特别视图的图层的位置的话,你可以重载相应视图的layoutSubviews方法,在这里面实现你定制的布局代码。你可以查看“iOS视图编程指南(View Programming Guide for iOS)”来获取更多关于如何在iOS应用里面基于视图的布局方法。

 

1.1 约束布局管理器

基于条件的布局允许你根据图层和它同级图层或者它的父图层的相应关系指定图层的位置和大小。通过CAConstraint类描述的关系被保存在子图层的constraints数组属性里面。

图1描述了在指定关系的的时候你可以使用的布局特性。

Figure 1  布局管理器constraints属性

 

 

当使用约束布局的时候,你首先创建一个CAConstraintLayoutManager的实例,并把它设置为父图层的布局管理器。然后你通过实例化CAConstraint对象为子图层创建约束条件,并把这些约束条件通过使用addConstraint:方法添加到子图层的约束属性里面。每个CAConstraint实例封装了一个两个图层在同一轴上的几何关系。

同级层引用的名称,使用图层的name属性。特定的名称superlayer被使用来引用图层的父图层。

每个轴上面最多只能指定两个关系。如果你给图层的左边和右边都指定约束关系,那么图层的宽度就会不同。如果你给图层的左边和宽度指定约束关系,则图层的右边就会从根据父图层的frame移动。通常你一般只会指定单个边的约束条件,图层在同一个轴上面的大小将会作为第二个约束关系。

代码1里面的示例代码创建了一个图层,然后使用位置约束条件添加子图层。图2描述了布局的结果。

Figure 2  基于示例中constraints的布局

 

 

代码 1  配置 layer的 constraints

// create and set a constraint layout manager for theLayer
theLayer.layoutManager=[CAConstraintLayoutManager layoutManager];
 
CALayer *layerA = [CALayer layer];
layerA.name = @"layerA";
 
layerA.bounds = CGRectMake(0.0,0.0,100.0,25.0);
layerA.borderWidth = 2.0;
 
[layerA addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintMidY
                                                 relativeTo:@"superlayer"
                                                  attribute:kCAConstraintMidY]];
 
[layerA addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintMidX
                                                 relativeTo:@"superlayer"
                                                  attribute:kCAConstraintMidX]];
 
[theLayer addSublayer:layerA];
 
CALayer *layerB = [CALayer layer];
layerB.name = @"layerB";
layerB.borderWidth = 2.0;
 
[layerB addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintWidth
                                                 relativeTo:@"layerA"
                                                  attribute:kCAConstraintWidth]];
 
[layerB addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintMidX
                                                 relativeTo:@"layerA"
                                                  attribute:kCAConstraintMidX]];
 
 
[layerB addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintMaxY
                                                 relativeTo:@"layerA"
                                                  attribute:kCAConstraintMinY
                                                     offset:-10.0]];
 
[layerB addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintMinY
                                                 relativeTo:@"superlayer"
                                                  attribute:kCAConstraintMinY
                                                     offset:+10.0]];
 
[theLayer addSublayer:layerB];

  

以上是代码执行过程:

  1. 创建一个CAConstraintLayoutmanager实例,然后把它设置为theLayer的layoutManger的属性。
  2. 创建一个CALayer(layerA)的实例,设置图层的name属性为“layerA”。
  3. 设置layerA的bounds为(0.0,0.0,10.0,25.0)。
  4. 创建一个CAConstraint对象,把它作为约束条件添加到layerA里面。该约束条件是把layerA的水平中心对齐它的父图层的水平中心。
  5. 创建第二个CAConstraint对象,把它作为layerA的约束条件。该约束条件是把layerA的垂直中心对齐父图层的垂直中心。
  6. 把layerA添加为theLayer的子图层。
  7. 创建一个CALayer(layerB)的实例,设置图层的name属性为“layerB”。
  8. 创建一个CAConstraint对象,给layerA添加该约束条件,该约束条件是设置layerB的宽度设置为与layerA的宽度相同。
  9. 创建第二个CAConstraint对象,把该约束条件添加到layerB里面。该约束条件是设置layerB的水平中心对齐layerA的水平中心。
  10. 创建第三个CAConstraint对象,并把它添加为layerB的约束条件。该约束条件设置layerB的顶边低于layerA底边10像素。
  11. 创建第四个CAConstraint对象,把它作为约束条件添加到layerB里面。该约束条件是把layerB的底边高于父图层底边10像素。

注意: 有可能创建约束条件导致在相同的属性的循环引用。在布局是无法计算的情况下,行为结果是不可预知的。

评论模块尚未加载