自动布局自动旋转时,如何重新排列视图?

我经常遇到这样的问题,我希望以一种方式来安排我的意见,而对于风景来说却有一种截然不同的方式。

对于一个简单的例子,请考虑以下几点:

肖像:

景观:

请注意,纵向上的图像是垂直堆叠的,但在横向上,它们是并排的?

当然,我可以手动计算位置和大小,但是对于更复杂的视图,这很快变得复杂。 另外,我更喜欢使用Autolayout,所以有更less的设备特定的代码(如果有的话)。 但是,这似乎是很多 Autolayout代码来编写的。 有没有办法通过故事板设置这种东西的约束?

Xcode的界面生成器有两个未被充分利用的特性,我们可以在这里使用这个来完成这种事情。

  1. 您可以为NSLayoutConstraints创buildIBOutlet连接。
  2. 您可以连接“出口集合”,这是一个IBOutlet对象的数组。

因此,考虑到这两点,我们要做的就是创build一个方向的所有自动布局约束,将它们全部挂在出口集合中。 现在,对于每个约束,取消选中界面构build器上的“已安装”选项。 然后把我们所有的socketscollections放到另一个布局中,然后把它们连接到另一个socketscollections。 我们可以根据需要创build尽可能多的这些布局组。

需要注意的是我们需要引用任何直接安装约束条件的UI元素,而且我们需要一个独立的出口集合,而不仅仅是我们想要的每个布局,而是直接安装在其上的每个UI对象。

我们来看看你的问题中相当简单的例子。

在这里输入图像说明

如果您查看左边的约束列表,可以看到其中一半是灰色的。 灰色约束是风景约束。 我创build了所有这些,然后取消选中“安装”为他们每个人:

在这里输入图像说明

与此同时,无约束,正常的约束是肖像约束。 对于这些,我把他们放在“安装”。 完全没有必要安装它们,但是如果你安装了多套(它们很可能会发生冲突),你将会遇到问题。

在这里输入图像说明

一定不要检查“在构build时删除”的任何这些。 我们不希望在构build时“删除”这些约束。 这仅仅意味着约束不会被创build(所以我们会失去对它的引用)。 如果我们让这个支票标记,而我们有一个IBOutlet的约束,Xcode会产生一个警告:

不支持的configuration
连接到占位符约束。 在IB中标记为占位符的约束应该没有任何连接,因为这些约束不会编译到文档中,并且在运行时不会存在。

无论如何,现在我们需要将约束条件连接到sockets,以便我们可以在运行时访问它们。

按住Ctrl并单击并从其中一个约束拖到源代码文件,就像连接任何其他UI元素一样。 在popup的对话框中,selectOutlet 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() } } 

Objective-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 

我们不检查视图以前有哪些约束集,所以只需删除两个约束集,然后添加我们想要使用的适当集合。

这是我们需要pipe理的所有代码,在运行时完全改变了对象上的一组约束。 这允许在界面生成器中工作,以设置所有的约束,而不是以编程方式(我发现有点乏味和容易出错)。

最终结果? 非常好看的自转重新排列,不拉你的头发得到完美的自动布局代码:

现在UIStackView在iOS9中可用,更简单和有保证的解决scheme是将两个视图添加到堆栈视图,将堆栈视图链接到IBOutlet,然后将以下代码添加到视图控制器:

 - (void) adjustViewsForOrientation:(UIInterfaceOrientation) orientation { if(orientation == UIInterfaceOrientationPortrait || orientation == UIInterfaceOrientationPortraitUpsideDown || orientation == UIInterfaceOrientationUnknown) self.stackView.axis = UILayoutConstraintAxisVertical; else self.stackView.axis = UILayoutConstraintAxisHorizontal; [self.stackView setNeedsLayout]; [self.stackView setNeedsDisplay]; 

}

并从中调用此方法

 -(void) willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration