使用自动布局自动旋转时如何重新排列视图? [英] How can I rearrange views when autorotating with autolayout?

查看:17
本文介绍了使用自动布局自动旋转时如何重新排列视图?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我经常遇到这个问题,我希望我的视图以一种方式排列纵向,而以一种完全不同的方式排列横向.

I frequently run into this problem where I want my views arranged in one manner for portrait and a somewhat drastically different manner for landscape.

对于一个简化的示例,请考虑以下内容:

For a simplified example, consider the following:

注意纵向图像是如何垂直堆叠的,而横向图像是并排的?

Notice how in portrait the images are stacked vertically, but in landscape, they are side-by-side?

当然,我可以手动计算位置和大小,但是对于更复杂的视图,这很快就会变得复杂.另外,我更喜欢使用 Autolayout,因此设备特定的代码更少(如果有的话).但这似乎需要编写 很多 的自动布局代码.有没有办法通过情节提要为这类东西设置约束?

Of course, I can manually calculate the positions and sizes, but for more complicated views, this quickly becomes complex. Plus, I'd prefer to use Autolayout so there's less device-specific code (if any at all). But that seems like a lot of Autolayout code to write. Is there a way to do set up the constraints for this sort of stuff through the storyboard?

推荐答案

我们可以在这里利用 Xcode 的界面构建器的两个未充分利用的特性来使这类事情完全同步.

There are two underused features of Xcode's interface builder we can make use of here to make exactly this sort of thing a synch.

  1. 您可以为 NSLayoutConstraints 创建 IBOutlet 连接.
  2. 您可以连接出口集合",这是一个 IBOutlet 对象数组.
  1. You can create IBOutlet connections for NSLayoutConstraints.
  2. You can hook up "outlet collections", which is an array of IBOutlet objects.

因此,考虑到这两件事,我们要做的要点是为一个方向创建所有自动布局约束,将它们全部连接到一个插座集合中.现在,对于这些约束中的每一个,取消选中界面生成器上的已安装"选项.然后为另一个布局制作我们所有的奥特莱斯系列,并将它们连接到另一个奥特莱斯系列.我们可以根据需要创建任意数量的布局组.

So with these two things in mind, the gist of what we want to do is create all of our autolayout constraints for one orientation, hook them all up in an outlet collection. Now, for each of these constraints, uncheck the "Installed" option on interface builder. Then make all of our outlet collections for another layout, and hook them up to another outlet collection. We can create as many of these layout groups as we want.

重要的是要注意,我们需要对任何直接安装了约束的 UI 元素的引用,并且我们需要一个单独的插座集合,不仅针对我们想要的每个布局,而且针对每个安装了约束的 UI 对象直接上.

It's important to note that we will need a reference to any UI element which has constraints installed on it directly, and we will need a seperate outlet collection not just for each layout we want, but for each UI object which has constraints installed on it directly.

让我们看一下您问题中相当简化的示例.

Let's take a look at the fairly simplified example from your question.

如果您查看左侧的约束列表,您会看到其中一半是灰色的.灰色的约束是景观约束.我创建了所有这些,然后为它们中的每一个取消选中已安装":

If you look in the constraints list on the left, you can see half of them are grayed-out. The grayed-out constraints are the landscape constraints. I created all of these, then unchecked "Installed" for each of them:

同时,未变灰的、正常外观的约束是纵向约束.对于这些,我将它们安装".完全没有必要安装其中的任何一个,但如果您安装了多个集合,则会遇到问题(它们很可能会发生冲突).

Meanwhile, the ungrayed, normal looking constraints are the portrait constraints. For these, I left them "Installed". It's completely unnecessary to leave any of them installed, but you will run into problems if you leave multiple sets installed (they most likely conflict).

请务必不要为其中任何一项选中在构建时删除".我们不希望在构建时移除"约束.这仅仅意味着根本没有创建约束(所以我们将失去对它的引用).如果我们在约束中有一个 IBOutlet 时标记此检查,Xcode 将生成一个警告:

Be sure not to check "Remove at build time" for any of these. We don't want the constraints "removed" at build time. This simply means the constraint isn't created at all (so we'll lose the reference to it). If we leave this check marked while we have an IBOutlet to the constraint, Xcode will generate a warning:

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

Unsupported Configuration
Connection to placeholder constraint. Constraints marked as placeholders in IB should not have any connections since these constraints are not compiled into the document and will not exist at runtime.

无论如何,现在我们需要将约束连接到一个出口,以便我们可以在运行时访问它们.

Anyway, so now we need to hook up the constraints to an outlet so we can access them at run time.

按住 Ctrl 并单击并从其中一个约束拖动到源代码文件,就像连接任何其他 UI 元素一样.在弹出的对话框中,选择 Outlet Collection 和一个描述性名称:

Hold Ctrl and click and drag from one of the constraints to your source code file, just as you would connect any other UI element. On the dialog that pops up, choose Outlet Collection and a descriptive name:

现在将与该约束组匹配的所有其他约束连接到同一个出口集合中:

Now hook up all of the other constraints that match that constraint group into the same outlet collection:

一旦我们完成了所有约束的关联,只需在适当的时间移除/添加它们即可.

Once we've finished hooking up all of our constraints, it's just a matter of removing/adding them at the appropriate time.

对于问题中描述的场景这样一个简单的例子,我们可以使用如下代码覆盖 updateViewConstraints:

For such a simple example as the scenario described in the question, we can override updateViewConstraints with some code like this:

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

我们不会检查视图之前的约束集,因此只需删除我们的两个约束集,然后添加我们想要使用的适当集.

We're not checking which set of constraints the view previously had, so just remove both of our constraint sets, and then add the appropriate set we want to use.

这是我们在运行时完全改变对象上的一整套约束所需的全部代码.这允许在界面构建器中设置我们所有的约束,而不必以编程方式进行(我发现这有点乏味且容易出错).

This is all the code we need to manage completely changing out an entire set of constraints on an object at run time. This allows to work in the interface builder to set all of our constraints up instead of having to do it programmatically (which I find a little more tedious and error-prone).

最终结果?非常漂亮的自动旋转重新排列,无需费力地完成自动布局代码:

The end result? Very nice looking autorotation rearrangement without pulling your hair out getting the autolayout code done perfectly:

这篇关于使用自动布局自动旋转时如何重新排列视图?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆