[TOC]
以下配方显示了如何使用堆栈视图来创建日益复杂的布局。 堆栈视图是快速轻松设计用户界面的强大工具。 他们的属性允许精确控制他们如何布置他们排列的视图。 可以使用其他自定义约束来增加这些设置; 然而,这增加了布局的复杂性。
要查看这些配方的源代码,请参阅 [Auto Layout Cookbook](https://developer.apple.com/sample-code/xcode/downloads/Auto-Layout-Cookbook.zip) 项目。
## 简单的堆栈视图
此配方使用单个垂直堆栈视图来布置文本标签,图像视图和按钮。
![](https://developer.apple.com/library/content/documentation/UserExperience/Conceptual/AutolayoutPG/Art/Simple_Stack_View_Screenshot_2x.png =387x629)
### 视图和约束
在 Interface Builder 中,首先拖出一个垂直堆栈视图,然后添加文本标签,图像视图和编辑按钮。 然后如图所示设置约束条件。
![](https://developer.apple.com/library/content/documentation/UserExperience/Conceptual/AutolayoutPG/Art/simple_stack_2x.png =252x441)
1. Stack View.Leading = Superview.LeadingMargin
2. Stack View.Trailing = Superview.TrailingMargin
3. Stack View.Top = Top Layout Guide.Bottom + Standard
4. Bottom Layout Guide.Top = Stack View.Bottom + Standard
### 属性
在“Attributes inspector”检查器中,设置以下堆栈视图属性:
| Stack |Axis| Alignment |Distribution | Spacing |
| --- | --- | --- | --- | --- |
| Stack View| Vertical | Fill | Fill | 8 |
接下来,在 ImageView 上设置以下属性:
| View | Attribute | Value |
| --- | --- | --- |
| Image View| Image | (an image of flowers) |
| Image View | Mode | Aspect Fit |
最后,在“ Size inspector”查器中,设置图像视图的内容拥抱和抗压缩(CHCR)优先级。
| Name | Horizontal hugging | Vertical hugging | Horizontal resistance | Vertical resistance |
| --- | --- | --- | --- | --- |
| ImageView | 250 |249 | 750 | 749 |
### 讨论
必须将堆栈视图固定到父视图,否则,堆栈视图将管理整个布局,而不会有任何其他显式约束。
在这个配方中,堆栈视图填充其超级视图,并有一个小的标准边界。 排列的视图被调整大小以填充堆栈视图的边界。 横向上,每个视图都被拉伸以匹配堆栈视图的宽度。 垂直方向上,视图基于其CHCR优先级而延伸。 图像视图应始终缩小、拉伸以填充可用空间。 因此,其垂直内容拥抱和压缩阻力优先级必须低于文本标签和按钮的默认优先级。
最后,将图像视图的模式设置为` Aspect Fit`。 此设置强制图像视图调整图像大小,使其适合图像视图的边界,同时保持图像的宽高比。 这可以让堆栈视图任意调整图像视图的大小而不会使图像失真。
有关固定视图以填充其父视图的更多信息,请参阅 [Attributes](https://developer.apple.com/library/content/documentation/UserExperience/Conceptual/AutolayoutPG/WorkingwithSimpleConstraints.html#//apple_ref/doc/uid/TP40010853-CH12-SW5) 和 [Adaptive Single View](https://developer.apple.com/library/content/documentation/UserExperience/Conceptual/AutolayoutPG/WorkingwithSimpleConstraints.html#//apple_ref/doc/uid/TP40010853-CH12-SW4)。
## 嵌套堆栈视图
这个配方显示了从多层嵌套堆栈视图构建的复杂布局。 然而,在这个例子中,堆栈视图不能单独创建想要的行为。 相反,需要额外的约束来进一步改进布局。
![](https://developer.apple.com/library/content/documentation/UserExperience/Conceptual/AutolayoutPG/Art/Nested_Stack_Views_Screenshot_2x.png =387x629)
在构建视图层次结构后,在下一节“视图和约束”中展示添加约束。
### 视图和约束
处理嵌套堆栈视图时,最容易的顺序是从内到外工作。 首先在 Interface Builder 中布置名称行。 将标签和文本字段放置在正确的相对位置,选择它们,然后单击 Editor > Embed In > Stack View 菜单项。 这会为该行创建一个水平堆栈视图。
接下来,水平放置这些行,选择它们,然后再次单击 Editor > Embed In > Stack View 菜单项。 这会创建一个水平的行堆栈。 继续构建如图所示的界面。
![](https://developer.apple.com/library/content/documentation/UserExperience/Conceptual/AutolayoutPG/Art/nested_stack_views_2x.png =537x565)
1. Root Stack View.Leading = Superview.LeadingMargin
2. Root Stack View.Trailing = Superview.TrailingMargin
3. Root Stack View.Top = Top Layout Guide.Bottom + 20.0
4. Bottom Layout Guide.Top = Root Stack View.Bottom + 20.0
5. Image View.Height = Image View.Width
6. First Name Text Field.Width = Middle Name Text Field.Width
7. First Name Text Field.Width = Last Name Text Field.Width
### 属性
每个堆栈都有自己的一组属性。 这些定义了堆栈如何布置其内容。 在属性检查器中,设置以下属性:
| Stack | Axis | Alignment |Distribution | Spacing |
| --- | --- | --- | --- | --- |
| First Name | Horizontal |First Baseline | Fill | 8 |
| Middle Name | Horizontal | First Baseline |Fill |8 |
| Last Name | Horizontal | First Baseline | Fill | 8 |
| Name Rows |Vertical |Fill | Fill | 8 |
| Upper | Horizontal | Fill | Fill | 8 |
| Button| Horizontal | First Baseline | Fill Equally | 8 |
| Root | Vertical | Fill | Fill | 8 |
此外,使文本视图呈浅灰色背景色。 这使得更容易看到文本视图在方向更改时如何调整大小。
| View |Attribute | Value |
| --- | --- | --- |
| Text View | Background | Light Gray Color |
最后,CHCR优先级定义哪些视图应该延伸以填充可用空间。 在 "Size inspector" 检查器中,设置以下CHCR优先级:
| Name | Horizontal hugging | Vertical hugging | Horizontal resistance | Vertical resistance |
| --- | --- | --- | --- | --- |
| Image View | 250 | 250 | 48 | 48 |
| Text View | 250 |249 | 250 |250 |
| First, Middle, and Last Name Labels | 251 | 251 | 750 | 750 |
| First, Middle, and Last Name Text Fields | 48 | 250 |749 |750 |
### 讨论
在这个配方中,堆栈视图一起工作来管理大部分布局。 但是,他们无法 - 自己 - 创造所有想要的行为。 例如,当图像视图被调整大小时,图像应该保持其纵横比。 不幸的是,简单堆栈视图中使用的技术在这里不起作用。 布局需要贴近图像的尾部和底部边缘,并且使用“宽高比拟合”模式会为其中一个维度添加额外的空白区域。 幸运的是,在这个例子中,图像的高宽比总是正方形的,所以你可以让图像完全填充图像视图的边界,并将图像视图限制为1:1的高宽比。
> 注意
> 在 Interface Builder 中,宽高比约束仅仅是视图高度和宽度之间的约束。 Interface Builder 还可以通过多种方式显示约束的乘数。 通常,对于宽高比限制,它将它们显示为比率。 因此,View.Width = View.Height 约束可能会显示为 1:1 宽高比。
此外,所有文本字段应该是相同的宽度。 不幸的是,它们都在单独的堆栈视图中,所以堆栈无法管理它。 相反,您必须明确添加相等宽度的约束。
就像简单的堆栈视图一样,您还必须修改一些CHCR优先级。 这些定义了视图如何随着超类的边界改变而缩小和增长。
垂直方向上,您希望文本视图展开以填充上层堆栈和按钮堆栈之间的空间。 因此,文本视图的垂直内容拥抱必须低于任何其他垂直内容拥抱优先权。
横向上,标签应显示为内在内容大小,而文本字段调整大小以填充任何额外空间。 默认的CHCR优先顺序适用于标签。 界面生成器已经在251设置拥抱内容,使其高于文本字段; 但是,您仍然需要降低文本字段的水平内容拥抱和水平压缩抵抗力。
图像视图应该缩小,以便与包含名称行的堆栈具有相同的高度。 但是,堆栈视图只是松散地拥抱他们的内容。 这意味着图像视图的垂直压缩阻力必须非常低,因此图像视图会缩小而不是展开堆栈视图。 此外,图像视图的高宽比约束使布局复杂化,因为它允许垂直和水平约束进行交互。 这意味着文本字段的横向内容拥抱也必须非常低,否则会阻止图像视图缩小。 在这两种情况下,请将优先级设置为48或更低。
## 动态堆栈视图
此配方演示了在运行时动态添加和删除堆栈中的项目。 对堆栈的所有更改都是动画形式的。 此外,堆栈视图放置在滚动视图中,如果它太长而无法放在屏幕上,则可以滚动列表。
![](https://developer.apple.com/library/content/documentation/UserExperience/Conceptual/AutolayoutPG/Art/Dynamic_Stack_View_Screenshot_2x.png =451x389)
> 注意
> 此配方仅用于演示动态使用堆栈视图以及在滚动视图内使用堆栈视图。 在现实世界的应用程序中,应该使用 UITableView 类来实现此配方的行为。 一般来说,您不应该使用动态堆栈视图来简单地实现基于划痕的表视图克隆。 相反,使用它们来创建动态用户界面,您无法使用任何其他技术轻松构建动态用户界面。
### 视图和约束
最初的用户界面非常简单。 在你的场景中放置一个滚动视图,并调整它的大小,使其充满场景。 然后,在滚动视图中放置一个堆栈视图,并将添加项按钮放入堆栈视图中。 只要一切就绪,请设置以下约束条件:
![](https://developer.apple.com/library/content/documentation/UserExperience/Conceptual/AutolayoutPG/Art/dynamic_stack_view_2x.png =291x379)
1. Scroll View.Leading = Superview.LeadingMargin
2. Scroll View.Trailing = Superview.TrailingMargin
3. Scroll View.Top = Superview.TopMargin
4. Bottom Layout Guide.Top = Scroll View.Bottom + 20.0
5. Stack View.Leading = Scroll View.Leading
6. Stack View.Trailing = Scroll View.Trailing
7. Stack View.Top = Scroll View.Top
8. Stack View.Bottom = Scroll View.Bottom
9. Stack View.Width = Scroll View.Width
### 属性
在“Attributes inspector”检查器中,设置堆栈视图以下属性:
| Stack | Axis | Alignment | Distribution | Spacing |
| --- | --- | --- | --- | --- |
| Stack View | Vertical | Fill | Equal Spacing | 0 |
### 代码
这个配方需要一些代码来添加项目并将其从堆栈视图中移除。 为您的场景创建自定义视图控制器,同时为滚动视图和堆栈视图提供插口。
~~~
class DynamicStackViewController: UIViewController {
@IBOutlet weak private var scrollView: UIScrollView!
@IBOutlet weak private var stackView: UIStackView!
// Method implementations will go here...
}
~~~
接下来,重写 viewDidLoad 方法来设置滚动视图的初始位置。 希望滚动视图的内容在状态栏下方开始。
~~~
override func viewDidLoad() {
super.viewDidLoad()
// setup scrollview
let insets = UIEdgeInsetsMake(20.0, 0.0, 0.0, 0.0)
scrollView.contentInset = insets
scrollView.scrollIndicatorInsets = insets
}
~~~
现在,为添加项目按钮添加一个操作方法。
~~~
// MARK: Action Methods
@IBAction func addEntry(sender: AnyObject) {
let stack = stackView
let index = stack.arrangedSubviews.count - 1
let addView = stack.arrangedSubviews[index]
let scroll = scrollView
let offset = CGPoint(x: scroll.contentOffset.x,
y: scroll.contentOffset.y + addView.frame.size.height)
let newView = createEntry()
newView.hidden = true
stack.insertArrangedSubview(newView, atIndex: index)
UIView.animateWithDuration(0.25) { () -> Void in
newView.hidden = false
scroll.contentOffset = offset
}
}
~~~
此方法计算滚动视图的新偏移量,然后创建新的条目视图。 输入视图是隐藏的,并添加到堆栈中。 隐藏的视图不会影响堆栈的外观或布局 - 所以堆栈的外观保持不变。 然后,在动画块中,显示视图并更新滚动偏移,为视图的外观添加动画。
添加一个类似的方法来删除条目; 但是,与 `addEntry` 方法不同,此方法未链接到 Interface Builder 中的任何控件。 相反,应用程序会在创建视图时以编程方式将每个条目视图链接到此方法。
~~~
func deleteStackView(sender: UIButton) {
if let view = sender.superview {
UIView.animateWithDuration(0.25, animations: { () -> Void in
view.hidden = true
}, completion: { (success) -> Void in
view.removeFromSuperview()
})
}
}
~~~
该方法将视图隐藏在动画块中。 动画完成后,它将从视图层次结构中删除视图。 这会自动从堆栈的排列视图列表中删除视图。
尽管入口视图可以是任何视图,但此示例使用包含日期标签,包含随机十六进制字符串的标签和删除按钮的堆栈视图。
~~~
// MARK: - Private Methods
private func createEntry() -> UIView {
let date = NSDateFormatter.localizedStringFromDate(NSDate(), dateStyle: .ShortStyle, timeStyle: .NoStyle)
let number = "\(randomHexQuad())-\(randomHexQuad())-\(randomHexQuad())-\(randomHexQuad())"
let stack = UIStackView()
stack.axis = .Horizontal
stack.alignment = .FirstBaseline
stack.distribution = .Fill
stack.spacing = 8
let dateLabel = UILabel()
dateLabel.text = date
dateLabel.font = UIFont.preferredFontForTextStyle(UIFontTextStyleBody)
let numberLabel = UILabel()
numberLabel.text = number
numberLabel.font = UIFont.preferredFontForTextStyle(UIFontTextStyleHeadline)
let deleteButton = UIButton(type: .RoundedRect)
deleteButton.setTitle("Delete", forState: .Normal)
deleteButton.addTarget(self, action: "deleteStackView:", forControlEvents: .TouchUpInside)
stack.addArrangedSubview(dateLabel)
stack.addArrangedSubview(numberLabel)
stack.addArrangedSubview(deleteButton)
return stack
}
private func randomHexQuad() -> String {
return NSString(format: "%X%X%X%X",
arc4random() % 16,
arc4random() % 16,
arc4random() % 16,
arc4random() % 16
) as String
}
}
~~~
### 讨论
* 如此配方演示,视图可以在运行时添加或从堆栈视图中删除。 堆栈的布局会自动调整以补偿其排列视图阵列的更改。 但是,有一些重要的值得记住的地方:
* 隐藏的视图仍然位于堆栈的排列视图阵列内。 但是,它们不会显示,也不会影响其他排列视图的布局。
* 将视图添加到堆栈的排列视图数组中会自动将其添加到视图层次结构中。
* 从堆栈的排列视图阵列中移除视图不会自动从视图层次中移除视图; 但是,从视图层次结构中删除视图会将其从排列的视图数组中移除。
* 在 iOS 中,视图的隐藏属性通常不是可以动画的。 然而,只要将这些属性放入堆栈排列的视图数组中,该属性就会变为动画。 实际的动画由堆栈管理,而不是视图。 使用隐藏属性来为视图添加视图或将其从堆栈中移除。
此配方还介绍了使用自动布局和滚动视图的想法。 这里,堆栈和滚动视图之间的约束设置滚动视图的内容区域的大小。 等宽限制显式设置堆栈(以及内容大小)以水平填充滚动视图。 垂直方向上,内容尺寸基于堆叠的配件尺寸。 随着用户添加更多条目,堆栈视图变长。 只要内容太多而无法在屏幕上显示,滚动就会自动启用。
有关更多信息,请参阅 [Working with Scroll Views](https://developer.apple.com/library/content/documentation/UserExperience/Conceptual/AutolayoutPG/WorkingwithScrollViews.html#//apple_ref/doc/uid/TP40010853-CH24-SW1)。
>原文地址
>[Stack Views ](https://developer.apple.com/library/content/documentation/UserExperience/Conceptual/AutolayoutPG/LayoutUsingStackViews.html#//apple_ref/doc/uid/TP40010853-CH11-SW12)