Auto Layout
经常引起抱怨的是,语法以编程方式创建约束的方式多么繁琐和难以理解。 幸运的是,iOS 9
做了很多改进。 堆栈视图
消除了我们在典型布局中创建许多约束的需要。 相比较而言,布局锚点和布局指南的引入却被忽略了,但同样有用。 从《 Apple自动版面指南》中:
在以编程方式创建约束时,你有三个选择:可以使用
layout anchors
,可以使用NSLayoutConstraint
类,或者可以使用可视格式语言。
我将再次看一下布局指南,但是现在这里是我关于使用布局锚点在代码中轻松创建约束的说明:
创建约束
首先提醒一下使用 NSLayoutConstraint
类方法创建约束的方式。 假设我们有一个堆栈视图,我们想要固定到视图控制器顶级视图的左右边距:
1 | NSLayoutConstraint(item: stackView, |
我们还可以将堆栈视图固定在顶部布局指南下方,以免被导航栏隐藏:
1 | NSLayoutConstraint(item: stackView, |
我认为我们可以同意,这既不美观也不容易理解( Objective-C
版本更糟)。 在我看来,使用 Visual Format Language 并不是更好:
1 | let views: [String: AnyObject] = |
使用 Layout Anchors
创建约束
布局锚点使创建约束更加容易。 从文档中:
NSLayoutAnchor
类是用于使用流畅的API
创建NSLayoutConstraint
对象的工厂类。 使用这些约束可以使用“自动布局”以编程方式定义你的布局。
布局锚点是 UIView
(或UILayoutGuide
)上的属性。 每个属性都是 NSLayoutAnchor
的子类,其方法可直接为其他相同类型的布局锚创建约束。 UIView
具有十二种不同的布局锚点属性,可用于创建水平,垂直或基于大小的约束:
水平约束
用于创建水平约束的 NSLayoutXAxisAnchor
类型的布局锚点:
centerXAnchor
leadingAnchor
和trailingAnchor
leftAnchor
和rightAnchor
例如,创建约束以使两个视图居中对齐:
1 | // Swift |
1 | // Objective-C |
请注意如何从一个视图上的锚点开始并为另一个视图上的锚点创建约束。
垂直约束
用于创建垂直约束的 NSLayoutYAxisAnchor
类型的布局锚点:
centerYAnchor
bottomAnchor
和topAnchor
firstBaselineAnchor
和lastBaselineAnchor
例如,要在间距恒定的两个视图的顶部和底部锚点之间创建约束:
1 | // Swift |
1 | // Objective-C |
基于 Size 的约束
NSLayoutDimension
类型的布局锚,用于创建基于 Size
的约束:
heightAnchor
和widthAnchor
例如,为视图创建宽度约束:
1 | // Swift |
1 | // Objective-C |
另一个示例,使用 multiplier
使一个视图的高度是另一个视图的高度的两倍:
1 | // Swift |
1 | // Objective-C |
视图边距
UIView
没有用于创建堆栈视图约束时使用的前,后边距的布局锚。 相反,iOS 9
添加了两个新属性, layoutMarginGuide
和可读 readableContentGuide
,它们又具有布局锚点。
例如,要将子视图的前沿约束到父视图的前面:
1 | // Swift |
1 | // Objective-C |
顶部和底部布局
提示:
顶部和底部布局指南已由iOS 11
中的“Safe Area Layout Guide ”
代替。
当你要相对于顶部或底部 UIKit
工具栏定位内容时,视图控制器具有 topLayoutGuide
和 bottomLayoutGuide
属性。 从 iOS 9
开始,这两个属性均符合 UILayoutSupport
协议,该协议为 bar
提供了 bottomAnchor
, topAnchor
和 heightAnchor
属性。
例如,要将视图放置在顶部布局指南底部下方8个点处:
1 | // Swift |
1 | // Objective-C |
控件组合布局
那么我们如何使用布局锚创建堆栈视图约束?
首先,我们获得父视图的 leading
和 trailing
边距:
1 | let margins = view.layoutMarginsGuide |
然后,我们创建 leading
和 trailing
水平约束:
1 | stackView.leadingAnchor.constraint(equalTo: margins.leadingAnchor).isActive = true |
最后,我们使用视图控制器的 topLayoutGuide
属性将堆栈视图固定在导航栏下方的8点处:
1 | stackView.topAnchor.constraint(equalTo: topLayoutGuide.bottomAnchor, |
Objective-C
版本稍微冗长一些,但仍有很大改进:
1 | UILayoutGuide *margins = self.view.layoutMarginsGuide; |
与以前的代码相比,我发现更容易理解这些约束的意图。