Xcode 的界面构建器有两个未被充分利用的特性,我们可以在这里利用这些特性来使这类事情完全同步。
- 您可以为
NSLayoutConstraints 创建IBOutlet 连接。
- 您可以连接“出口集合”,它是
IBOutlet 对象的数组。
因此,考虑到这两件事,我们要做的主要是为一个方向创建所有自动布局约束,将它们全部连接到一个插座集合中。现在,对于这些约束中的每一个,取消选中界面生成器上的“已安装”选项。然后为另一个布局制作我们所有的奥特莱斯系列,并将它们连接到另一个奥特莱斯系列。我们可以根据需要创建任意数量的布局组。
需要注意的是,我们需要一个对直接安装了约束的 UI 元素的引用,并且我们需要一个单独的插座集合,不仅针对我们想要的每个布局,还针对每个安装了约束的 UI 对象直接上。
让我们看一下您问题中相当简化的示例。
如果您查看左侧的约束列表,您会看到其中一半是灰色的。灰色的约束是景观约束。我创建了所有这些,然后为它们中的每一个取消选中“已安装”:
同时,未变灰的、正常外观的约束是纵向约束。对于这些,我将它们“安装”。完全没有必要安装其中的任何一个,但如果您安装了多个集合,您会遇到问题(它们很可能会发生冲突)。
请务必不要为其中任何一项选中“在构建时删除”。我们不希望在构建时“移除”约束。这仅仅意味着根本没有创建约束(因此我们将失去对它的引用)。如果我们在约束条件中有IBOutlet 时保留此检查标记,Xcode 将生成警告:
不支持的配置
连接到占位符约束。在 IB 中标记为占位符的约束不应有任何连接,因为这些约束未编译到文档中,并且在运行时不存在。
无论如何,现在我们需要将约束连接到一个插座,以便我们可以在运行时访问它们。
按住 Ctrl 并单击并从其中一个约束拖动到源代码文件,就像连接任何其他 UI 元素一样。在弹出的对话框中,选择 Outlet Collection 和一个描述性名称:
现在将与该约束组匹配的所有其他约束连接到同一个出口集合中:
一旦我们完成了所有约束的连接,只需在适当的时间移除/添加它们即可。
对于问题中描述的场景这样一个简单的例子,我们可以用这样的代码覆盖updateViewConstraints:
斯威夫特
class ViewController: UIViewController {
@IBOutlet var landscapeConstraints: [NSLayoutConstraint]!
@IBOutlet var portraitConstraints: [NSLayoutConstraint]!
override func updateViewConstraints() {
let isPortrait = self.view.bounds.width < self.view.bounds.height
self.view.removeConstraints(self.portraitConstraints)
self.view.removeConstraints(self.landscapeConstraints)
self.view.addConstraints(isPortrait ? self.portraitConstraints : self.landscapeConstraints)
super.updateViewConstraints()
}
}
目标-C
@interface ViewController()
@property (strong, nonatomic) IBOutletCollection(NSLayoutConstraint) NSArray *landscapeConstraints;
@property (strong, nonatomic) IBOutletCollection(NSLayoutConstraint) NSArray *portraitConstraints;
@end
@implementation ViewController
- (void)updateViewConstraints {
BOOL isPortrait = self.view.bounds.size.width < self.view.boudns.size.height;
[self.view removeConstraints:self.portraitConstraints];
[self.view removeConstraints:self.landscapeConstraints];
[self.view addConstraints:(isPortrait ? self.portraitConstraints : self.landscapeConstraints)];
[super updateViewConstraints];
}
@end
我们不会检查视图之前的约束集,因此只需删除我们的两个约束集,然后添加我们想要使用的适当集。
这是我们在运行时完全改变对象上的一整套约束所需的全部代码。这允许在界面构建器中设置我们所有的约束,而不必以编程方式进行(我发现这有点乏味且容易出错)。
最终结果?非常漂亮的自动旋转重新排列,无需费力就可以完美完成自动布局代码: