自动布局中的弹簧:在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”视图:
-
确定顶部和底部button的位置。
-
在所有button之间放置间隔视图。 使用约束来水平放置它们(水平居中最简单)并设置它们的宽度。
-
在每个button与上下的间隔视图之间进行约束,常量为0。
-
现在select所有的spacer视图并将其高度设置为相等。
第一个屏幕截图显示我在IB中设置:
我故意没有纠正“错位的意见”,因为我想让你看看我devise约束时的样子。 这是在4英寸和3.5英寸的屏幕上的结果:
我已经将间隔视图留下了黑色,只是为了向您展示这种技术是如何工作的,但当然在现实生活中,您会使它们变得透明,因此不可见! 所以用户只能看到你的button,均匀分布在屏幕的任何一个高度。
使用这种技术的原因是,虽然平等的概念执行你所要求的价值分配,但是约束只能在视图的各个方面之间应用平等; 因此我们需要额外的视图(spacer视图),以便我们可以使其他事物(这里是间隔视图的高度)相等。
其他方法
显然,更灵活的方法是在代码中分配约束。 这可能听起来令人生畏,但是有很多第三方代码可以帮助你,比如这样的事情 。
例如,如果我们有一个(可能不可见的)超视图,它的高度作为一个边界来指定我们四个button的最大垂直分布,我们可以将它们的顶端固定在该超视图的垂直中心, constant
为0
但multiplier
为0.000001
, 0.666667
和2.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) ])
(很明显,我可以使用循环来使代码变得更短,但是我为了清晰起见故意将循环展开,以便您可以看到模式和技术。)