翻译@Auto Layout Guide(自动布局指南)


Auto Layout Cookbook(自动布局使用手册)

Simple Constraints(利用简单约束布局)

本节通过实际例子展示简单约束的使用,实现常见布局效果,为复杂布局打下基础。

具体源码详见项目Auto Layout Cookbook

Simple Single View(一个简单视图)

本例中,我们让红色视图填充父视图,但四边保留一定间距。

图31

Views and Constraints(搭建布局)

拖拽视图到画布,调整其大小以填满根视图。对齐边缘时,以IB提示的蓝色虚线为准(这是系统给出的对齐建议)。

注意

前期布局不必精确到像素级别。添加约束后,视图位置和尺寸会相应更新。

然后按照下图添加约束:

图32

  1. Red View.Leading = Superview.LeadingMargin
  2. Red View.Trailing = Superview.TrailingMargin
  3. Red View.Top = Top Layout Guide.Bottom + 20.0
  4. Bottom Layout Guide.Top = Red View.Bottom + 20.0
Attributes(设置属性)

给视图一个红色背景。打开属性面板,设置如下:

View Attribute Value
Red View Background Red
Discussion(分析&讨论)

本例中红色视图到父视图的边距固定。前后相对父视图留白约束;上下相对控制器的布局参照约束。

注意

根视图的留白由系统决定,前后为16或20pt(根据设备不同),上下为0pt。后者的用意在于将根视图内容显示在栏位下方(状态栏,导航栏,标签栏,工具栏等)。

然而,本例的内容(红色视图)需要置于上下栏位之间(如有)。因此,上下必须相对控制器的布局参照约束。

IB推荐父子视图间距为20pt;子视图之间为8pt。这意味着红色视图与状态栏之间的距离应为8pt。但是,设备横屏后状态栏随之消失,此时8pt又显得太窄。

要根据具体情况布局。本例中红色视图上下间距都是20pt,一来保证约束尽可能简单;二来在各种设备方向下都有合理的显示效果。当然,其他情况下8pt可能更合适。

如果想要根据栏位存在与否调整布局, 参见章节Adaptive Single View(一个自适应视图)

Adaptive Single View(一个自适应视图)

同上一个例子类似,这次我们布局一个蓝色视图,使它填充父视图,但四边保留一定间距。不同的是,上方间距根据显示环境变化。如果有状态栏,则间距为8pt(与状态栏之间);如果没有,则间距为20pt(与父视图之间)。

图33

通过对比两个例子,可以看出明显区别。

图34

Views and Constraints(搭建布局)

拖拽视图到画布,调整其大小以填满根视图。对齐边缘时,以IB提示的蓝色虚线为准(这是系统给出的对齐建议)。然后按照下图添加约束:

图35

  1. Blue View.Leading = Superview.LeadingMargin
  2. Blue View.Trailing = Superview.TrailingMargin
  3. Blue View.Top = Top Layout Guide.Bottom + Standard (Priority 750)
  4. Blue View.Top >= Superview.Top + 20.0
  5. Bottom Layout Guide.Top = Blue View.Bottom + Standard (Priority 750)
  6. Superview.Bottom >= Blue View.Bottom + 20.0
Attributes(设置属性)

给视图一个蓝色背景。打开属性面板,设置如下:

View Attribute Value
Blue View Background Blue
Discussion(分析&讨论)

蓝色视图上下边距可以动态变化:如果有栏位,则间距为8pt。如果没有,则间距为20pt。

我们使用了控制器的布局参照,其位置根据栏位是否存在,及存在时的高度变化。上方布局参照代表所有上方栏位的最下沿(例如,状态栏和导航栏同时存在,以后者下沿为准);下方布局参照代表所有下方栏位的最上沿(例如,标签栏);如果没有栏位,则代表父视图边缘。

上下各使用一对约束实现自适应效果。一条大于等于约束确保蓝色视图到父视图至少有20的距离,即最小间距20pt。

还有一条可选约束要求蓝色视图距离控制器的布局参照8pt。系统处理可选约束的原则是”尽量满足”:它就像弹簧一样,拉近蓝色视图和布局参照之间的距离。

如果没有栏位,布局参照等同于父视图边缘。蓝色视图无法同时满足8pt和20pt的间距。可选约束只能尽量满足——间距为20pt。

如果有栏位,则两个约束都得以满足:因为栏位高度至少为20pt。如果蓝色视图到栏位的距离为8pt,那么到父视图的距离肯定大于20pt。

互斥约束是实现自适应布局的常见手段。章节Views with Intrinsic Content Size(利用固有尺寸布局)专门讨论内缩和外扩优先级,其中再次用到了这一技巧。

Two Equal-Width Views(两个等宽视图)

这次我们并排布局两个视图:不论外部尺寸如何变化,二者总是等宽,且共同填充父视图空间,四边间距固定,彼此间距标准。

图36

Views and Constraints(搭建布局)

拖拽两个视图到画布,并排摆放,调整大小使它们均分整个空间。视图间距以IB提示的蓝色虚线为准。

无须担心两个视图宽度不等,只要相对位置正确即可,具体frame计算交给约束完成。

所有视图就位后,按照下图添加约束:

图37

  1. Yellow View.Leading = Superview.LeadingMargin
  2. Green View.Leading = Yellow View.Trailing + Standard
  3. Green View.Trailing = Superview.TrailingMargin
  4. Yellow View.Top = Top Layout Guide.Bottom + 20.0
  5. Green View.Top = Top Layout Guide.Bottom + 20.0
  6. Bottom Layout Guide.Top = Yellow View.Bottom + 20.0
  7. Bottom Layout Guide.Top = Green View.Bottom + 20.0
  8. Yellow View.Width = Green View.Width
Attributes(设置属性)

打开属性面板,设置如下:

View Attribute Value
Yellow View Background Yellow
Green View Background Green
Discussion(分析&讨论)

两个视图的上下间距被分别定义,只要间距相等,二者高度也相等。当然,等高效果不止一种实现方式:让两个视图上下对齐也可以实现同样效果,而且意图更明确。

这个布局很简单,有多种实现方式,各有优缺点。有些方式意图可能更明确,但效果都一样。我们所采用的方式主要有两个优点:首先,也是最重要的,简单易懂;其次,如果移除一个视图,另一个基本不受影响。

从视图结构中移除视图,相关约束也会一并移除。假设我们移除黄色视图,那么约束1,2,4,6,8也会移除。此时绿色视图还剩下3条约束,只需再添加1条限制前边的约束,布局就得以补全。

讨厌的是上下约束必须总是保持一致。修改一个约束的常量,另一个也要相应修改。通过固定工具创建约束,只需正确填写常量;通过拖拽创建约束,修改常量要麻烦一些。

那么,要如何选择呢?答案是结合需求,选择其中最易懂,最易维护的。假设要垂直居中一组大小不一的视图,很明显水平中心(Center X)对齐是明智的选择。但对于其他布局,也许对齐前后或宽高相等更好。

更多关于选择最佳布局实现方式的信息,详见章节Creating Nonambiguous, Satisfiable Layouts(创建明确且可满足布局)

Two Different-Width Views(两个不等宽视图)

这次的布局和Two Equal-Width Views(两个等宽视图)十分类似。区别在于,橘色视图的宽度总是紫色视图的两倍。

图38

Views and Constraints(搭建布局)

老样子,拖拽两个视图到画布,摆放到大致位置,随后按照下图添加约束:

图39

  1. Purple View.Leading = Superview.LeadingMargin
  2. Orange View.Leading = Purple View.Trailing + Standard
  3. Orange View.Trailing = Superview.TrailingMargin
  4. Purple View.Top = Top Layout Guide.Bottom + 20.0
  5. Orange View.Top = Top Layout Guide.Bottom + 20.0
  6. Bottom Layout Guide.Top = Purple View.Bottom + 20.0
  7. Bottom Layout Guide.Top = Orange View.Bottom + 20.0
  8. Orange View.Width = 2.0 x Purple View.Width
Attributes(设置属性)

打开属性面板,设置如下:

View Attribute Value
Purple View Background Purple
Orange View Background Orange
Discussion(分析&讨论)

系数2.0表示橘色视图的宽度是蓝色视图的两倍:系数只能用于约束宽高;宽高可以来自任意视图,或同一个视图。

IB允许我们通过多种格式表示系数:如十进制(2.0),百分制(200%),分数(2/1)或比例(2:1)。

Two Views with Complex Widths(两个拥有复杂宽度比的视图)

这次的布局几乎和Two Different-Width Views(两个不等宽视图)一致。区别在于二者有着复杂的宽度比:红色视图的宽度”最好”为蓝色视图的两倍,但蓝色视图的最小宽度是150pt。竖屏时二者宽度几乎相等;横屏时二者都变宽,但红色视图的宽度是蓝色视图的两倍。

图40

Views and Constraints(搭建布局)

按照要求摆放视图,随后按照下图添加约束:

图41

  1. Blue View.Leading = Superview.LeadingMargin
  2. Red View.Leading = Blue View.Trailing + Standard
  3. Red View.Trailing = Superview.TrailingMargin
  4. Blue View.Top = Top Layout Guide.Bottom + 20.0
  5. Red View.Top = Top Layout Guide.Bottom + 20.0
  6. Bottom Layout Guide.Top = Blue View.Bottom + 20.0
  7. Bottom Layout Guide.Top = Red View.Bottom + 20.0
  8. Red View.Width = 2.0 x Blue View.Width (Priority 750)
  9. Blue View.Width >= 150.0
Attributes(设置属性)

打开属性面板,按照下表设置属性:

View Attribute Value
Blue View Background Blue
Red View Background Red
Discussion(分析&讨论)

我们利用一对约束保证二者的宽度比符合预期:可选约束规定红色视图的宽度是蓝色视图的两倍;必要约束规定蓝色视图的宽度大于等于150pt。

事实上,如果扣除留白后的父视图宽度大于等于458.0pt(150.0 + 300.0 + 8.0),则能够满足可选约束。如果小于,则蓝色视图宽度固定为150.0pt,红色视图占据剩余空间。(还要减去8.0pt的间距)

上述技巧其实和Adaptive Single View(单一自适应视图)中的如出一辙。

我们可以进一步拓展这个布局——例如再添加3条约束:一个必要约束规定红色视图的最小宽度;一个高优先级约束规定蓝色视图的最小宽度;一个低优先级约束定义二者宽度比。