我想在一个视图中布置 6 个对象(按钮)。但是,它们应该遵循一些限制:
A
两个顶部按钮应与 superview ( )具有相同的垂直距离- 两个底 - 相同 (
C
) - 中间的两个应该有他们的中心在superview的中心线
- 所有按钮 ( ) 之间的垂直距离
E
应相同 - 最后但并非最不重要 - 按钮应该是方形的(所以宽度和高度应该相同)
A
=C
B
=D
是否可以仅在 IB 中产生这种效果,或者我应该为约束使用一些额外的代码?
我想在一个视图中布置 6 个对象(按钮)。但是,它们应该遵循一些限制:
A
两个顶部按钮应与 superview ( )具有相同的垂直距离C
)E
应相同A
=C
B
=D
是否可以仅在 IB 中产生这种效果,或者我应该为约束使用一些额外的代码?
这是一个逻辑请求,但是约束是使用视图的属性定义的,但不能相对于其他约束来定义。话虽如此,有多种方法:
布局指南:一种不需要预先确定任何间距的方法是使用UILayoutGuide
对象,或者,如果使用 iOS 9 之前的版本,只需在按钮之间使用隐藏视图,即具有清晰背景或 alpha 为零的视图。
这个想法是在您的六个按钮之间添加这些布局指南addLayoutGuide
(或添加不可见视图,addSubview
如果支持 iOS 9 之前的 iOS 版本)作为“间隔”,并将间隔定义为彼此相同的大小,并且在间隔,超级视图和将进入间隔之间的按钮。布置好之后(以蓝色显示水平间隔视图,以红色显示垂直间隔视图,以便您可以看到它们):
这些红色UIView
对象的约束的等效 VFL 称为vspacerX
,将是:
H:|[vspacer1][button1(100)][vspacer2(==vspacer1)][button2(==button1)][vspacer3(==vspacer1)]| H:|[vspacer1][button3(==button1)][vspacer2][button4(==button1)][vspacer3]| H:|[vspacer1][button5(==button1)][vspacer2][button6(==button1)][vspacer3]|
蓝色UIView
对象上的约束,称为hspacerX
,例如:
V:|[hspacer1][button1(100)][hspacer2(==hspacer1)][button3(==button1)][hspacer3(==hspacer1)][button5(==button1)][hspacer4(==hspacer1 )]| V:|[hspacer1][button2(==button1)][hspacer2][button4(==button1)][hspacer3][button6(==button1)][hspacer4]|
您不必使用 VFL 来定义这些约束,因为您定义这些约束的任何方式都可以,但它只是描述我使用的约束集合的简明格式。
无论如何,当使用这些布局指南(或不可见的视图)渲染视图时,它会产生均匀间隔的按钮,如下所示:
另一种方法是有六个“容器”视图,如下所示:
这六个容器UIView
对象的等效 VFL 可能如下所示:
H:|[容器1][容器2(==容器1)]| H:|[container3(==container1)][container4(==container1)]| H:|[container5(==container1)][container6(==container1)]| V:|[container1][container3(==container1)][container5(==container1)]| V:|[container2(==container1)][container4(==container1)][container6(==container1)]|
然后,您可以将按钮添加到其中,在六个小容器中的每一个上居中一个,然后使您的容器清晰:
这也有效,只是间距略有不同(其中边距是视图之间间距的一半,而另一种方法使边距与它们之间的间距相同。
堆栈视图:在前一点的排列中,在 iOS 9 中,您还可以使用UIStackView
, 专为均匀间距视图而设计。在这种情况下,将两个按钮分别放在三个水平堆栈视图中,然后将这些堆栈视图放置在垂直堆栈视图中。这实现了六个大小均匀的容器视图。
请参阅 WWDC 2015 视频Cocoa Touch 中的新增功能。
堆栈视图的问题在于它们可用于确保排列的子视图之间的间距均匀,它们不能确保在第一个排列视图之前或最后一个排列视图之后的间距。因此,解决这个问题的方法是,对于水平堆栈视图,包括另外两个零宽度视图(或垂直堆栈视图的零高度)。然后,当您在堆栈视图上使用均匀间距时,它还会为您提供所有排列的子视图之前和之后的间距。
NSLayoutAttributeCenterX
with multiple
:另一种技术涉及为六个按钮定义attribute:NSLayoutAttributeCenterX
andattribute:NSLayoutAttributeCenterY
属性,但不是使用constant
值,而是使用multiplier
字段。这种技术有点简单,但并不总是能呈现出想要的效果,所以我不会描述它,除非它是你确实想要追求的东西。我已经在这里进入了 tl:dr 领域。
集合视图:另一种方法是使用 a UICollectionView
,它可以优雅地处理这种情况。它经过精心设计,可让您在网格中布局单元格。
硬编码值:为了完整起见,我注意到您可以简单地为 A、B、C 和 D 指定特定值(以及宽度和高度约束)。您甚至不必担心设置 E 约束,只需将中间两个的垂直中心约束设置为它们的超级视图,您就可以有效地完成(因为 E 表示的间距应该是自然的结果前面的步骤,假设 A=C 和 B=D)。如果要根据设备大小和/或方向调整这些值,则可以实现 aviewWillLayoutSubviews
以根据视图大小调整这些约束的常量。
更新:我有一个更好的解决方案,不使用垫片。在这里查看。
好的,这在 IB 中可以很快实现。就是这么简单。这是一个有助于说明的图表。
假设 v1-6 是您的按钮,s1-5 是您的垫片。1) 在 IB 控件中拖出红线所示的所有连接。
2) shift click v1-6 and pin icon (看起来像 |-I-| ) 将宽度和高度设置为一个确定的值。另外,将高度和宽度设置为相等。
3)移位选择s1-4(不是5)并将高度设置为相等。不要给它一个明确的高度,因为这应该由系统计算。您可能还需要将 s1-4 的宽度设置为相等,但不要给它们一个明确的宽度。
4)控制从中心视图拖动到前缘和后缘并设置中心约束。
所以,你可能会想,好吧,现在应该可以了。它没有。这是我的应用程序以纵向运行,颜色略有不同。看起来不错。(请注意,一旦设置好垫片,您就会使其不可见)。
但是当我旋转时,哎呀!
这里发生了什么事?一旦我们了解出了什么问题,这个问题就非常容易解决。我们希望IB不要缩小我们的观点。我们希望 IB 使间隔和空间根据需要缩小和增长,但不要理会我们的观点。基本上,IB 在纵向上尽可能地缩小了垫片,并试图让一切都适合 IB 缩小了我们的观点。但我们希望 IB 缩小视图和分隔符之间的垂直空间,而不是我们的视图。解决方案非常简单。我们所要做的就是调整垂直空间的优先级,一切都很好。因此,选择 IB 中的垂直间距并将优先级调整为 750。垂直间距线将显示为虚线。完毕。
好的,这就是我们所期望的一切。
并明确了垫片: