自动布局中的弹簧:在Xcode 5中均匀地分配视图,带有约束

我理解在Interface Builder中alignment,分级和分配视图的旧的Struts和Springs方法。 然而,我似乎无法弄清楚如何使用Xcode 5自动布局均匀分布视图。有一种方法可以使用Xcode 4来完成,但是这个选项已经不存在了。

我有7个button排列在一个垂直的堆栈。 在3.5英寸的布局上,它看起来不错,当我在4“布局中预览屏幕时,所有的button都保持紧凑,最后一个button下面有大量的空间。

我希望他们保持相同的高度,但我希望他们之间的空间能够弯曲,以便他们可以散布在屏幕上。

在这里输入图像描述

我已经能够获得button的高度弯曲和填充空间,但这不是我想要的行为。 我想学习如何使用自动布局来取代我的老泉的行为,但我似乎无法find任何方式通过Interface Builder来做到这一点。

我确定顶部button既可以是顶部边缘的固定空间,也可以是顶部边缘的比例空间,同样也适用于底部button和底部边缘。 这些对我来说不那么重要,我也很好。

但我真的需要弄清楚如何均匀分配视图中每个项目之间的额外空间。

编辑请注意,在iOS 9中,此技术将变得不必要,因为UIStackView将自动执行分发。 我会添加另一个解释如何工作的答案 。

如何使用Autolay执行均匀分配

在Interface Builder中单独完成此操作的最简单的方法是使用“spacer”视图:

  1. 确定顶部和底部button的位置。

  2. 在所有button之间放置间隔视图。 使用约束来水平放置它们(水平居中最简单)并设置它们的宽度。

  3. 在每个button与上下的间隔视图之间进行约束,常量为0。

  4. 现在select所有的spacer视图并将其高度设置为相等。

第一个屏幕截图显示我在IB中设置:

在这里输入图像描述

我故意没有纠正“错位的意见”,因为我想让你看看我devise约束时的样子。 这是在4英寸和3.5英寸的屏幕上的结果:

在这里输入图像描述

我已经将间隔视图留下了黑色,只是为了向您展示这种技术是如何工作的,但当然在现实生活中,您会使它们变得透明,因此不可见! 所以用户只能看到你的button,均匀分布在屏幕的任何一个高度。

使用这种技术的原因是,虽然平等的概念执行你所要求的价值分配,但是约束只能在视图的各个方面之间应用平等; 因此我们需要额外的视图(spacer视图),以便我们可以使其他事物(这里是间隔视图的高度)相等。

其他方法

显然,更灵活的方法是在代码中分配约束。 这可能听起来令人生畏,但是有很多第三方代码可以帮助你,比如这样的事情 。

例如,如果我们有一个(可能不可见的)超视图,它的高度作为一个边界来指定我们四个button的最大垂直分布,我们可以将它们的顶端固定在该超视图的垂直中心, constant0multiplier0.0000010.6666672.0 (如果我们有四个button); 现在button将保持垂直分布,即使超视图改变大小以响应屏幕高度或其他。 [在Xcode 5.1中,可以在Interface Builder中进行设置,但在Xcode的早期版本中是不可能的。]

在iOS 9 / Xcode 7中,这个问题将在IB中得到解决。 只需selectbutton(或垂直分配的任何button),然后select“编辑器”>“embedded”>“堆叠视图”。 那么你只需configuration堆栈视图:

  • 提供对堆栈视图本身的位置和大小的约束。 例如,将堆栈视图的四个边钉在其超视图的四个边上。

  • 设置堆栈视图的属性。 在这种情况下,我们需要垂直轴,填充alignment,等距分布。

就这样! 但是,您可能对这是如何工作感到好奇,因为仍然可以在代码中手动执行相同的操作。 堆栈视图执行分发,而不是通过插入间隔视图 ,而是插入间隔指南 。 一个指南(UILayoutGuide)是一个轻量级的对象,就布局约束而言,它的行为就像一个视图,但不是一个视图,因此不一定是不可见的,并且不带有任何视图的开销。

为了说明,我将在代码中进行堆栈视图的操作。 假设我们有四个垂直分布的视图。 我们把它们的约束分配给它们,

  • 他们都有绝对的高度限制

  • 他们的左边是固定在超级观点的左边,右边是固定在超级观点的右边

  • 顶视图的顶部固定到超视图的顶部,而底部视图的底部固定到超视图的底部

现在,假设我们将四个视图引用为views ,一个数组。 然后:

 let guides = [UILayoutGuide(), UILayoutGuide(), UILayoutGuide()] for guide in guides { self.view.addLayoutGuide(guide) } NSLayoutConstraint.activateConstraints([ // guide heights are equal guides[1].heightAnchor.constraintEqualToAnchor(guides[0].heightAnchor), guides[2].heightAnchor.constraintEqualToAnchor(guides[0].heightAnchor), // guide widths are arbitrary, let's say 10 guides[0].widthAnchor.constraintEqualToConstant(10), guides[1].widthAnchor.constraintEqualToConstant(10), guides[2].widthAnchor.constraintEqualToConstant(10), // guide left is arbitrary, let's say superview margin guides[0].leftAnchor.constraintEqualToAnchor(self.view.leftAnchor), guides[1].leftAnchor.constraintEqualToAnchor(self.view.leftAnchor), guides[2].leftAnchor.constraintEqualToAnchor(self.view.leftAnchor), // bottom of each view is top of following guide views[0].bottomAnchor.constraintEqualToAnchor(guides[0].topAnchor), views[1].bottomAnchor.constraintEqualToAnchor(guides[1].topAnchor), views[2].bottomAnchor.constraintEqualToAnchor(guides[2].topAnchor), // top of each view is bottom of preceding guide views[1].topAnchor.constraintEqualToAnchor(guides[0].bottomAnchor), views[2].topAnchor.constraintEqualToAnchor(guides[1].bottomAnchor), views[3].topAnchor.constraintEqualToAnchor(guides[2].bottomAnchor) ]) 

(很明显,我可以使用循环来使代码变得更短,但是我为了清晰起见故意将循环展开,以便您可以看到模式和技术。)