Autolayout - 平均分配6个视图

时间:2013-10-11 20:55:12

标签: xcode interface-builder autolayout

我希望在一个视图中放置6个对象(按钮)。但是,他们应该遵循一些限制:

enter image description here

  • 两个顶部按钮应与superview(A
  • 具有相同的垂直距离
  • 两个底部 - 相同(C
  • 中间的两个中心应该在超级视图的中心线上
  • 所有按钮(E)之间的垂直距离应相同
  • 并且最后但并非最不重要 - 按钮应该是方形的(因此宽度和高度应该相同)
  • A = C
  • B = D

是否可以在IB中产生这种效果,还是应该使用一些额外的代码来约束?

2 个答案:

答案 0 :(得分:23)

这是一个逻辑请求,但约束是使用视图的属性定义的,但不能相对于其他约束定义。话虽如此,有很多方法:

  1. 布局指南:不需要预先确定任何间距的方法是拥有UILayoutGuide个对象,或者如果在9之前使用iOS版本,则只使用隐藏视图,即按钮之间的背景清晰或零度为α的视图。

    我们的想法是使用addLayoutGuide添加这些布局指南(或者如果在iOS 9之前支持iOS版本,则使用addSubview添加不可见的视图)在六个按钮之间作为“间隔符”,并定义间隔符彼此相同的尺寸,以及间隔物,超视图和间隔物之间​​的按钮之间的约束。一旦你把它放在外面(用蓝色显示水平间隔视图,用红色显示垂直间隔视图,这样就可以看到它们):

    spacer views

    那些名为UIView的红色vspacerX对象的约束的等效VFL将是:

    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来定义这些约束,因为您定义这些约束的任何方式都可以,但它只是一种简洁的格式,用于描述我使用的约束集合。

    无论如何,当使用那些布局指南(或不可见的视图)渲染视图时,它会产生均匀间隔的按钮,如下所示:

    spacers hidden

  2. 另一种方法是拥有六个“容器”视图,如下所示:

    containers

    这六个容器UIView对象的等效VFL可能如下所示:

    H:|[container1][container2(==container1)]|
    H:|[container3(==container1)][container4(==container1)]|
    H:|[container5(==container1)][container6(==container1)]|
    
    V:|[container1][container3(==container1)][container5(==container1)]|
    V:|[container2(==container1)][container4(==container1)][container6(==container1)]|
    

    然后,您可以将按钮添加到其中,在六个小容器中的每个容器上居中,然后清空容器:

    just buttons

    这也有效,但间距略有不同(边距是视图之间间距的一半,而另一种方法使边距与它们之间的间距相同。

  3. 堆栈视图:在前一点的排列中,在iOS 9中,您还可以使用UIStackView,专为均匀间隔视图而设计。在这种情况下,将两个按钮分别放在三个水平堆栈视图中,然后将这些堆栈视图放在垂直堆栈视图中。这实现了六个大小均匀的容器视图。

    参见WWDC 2015视频What's New in Cocoa Touch

    堆栈视图的问题在于它们可用于确保排列的子视图之间的间距均匀,它们不能确保在第一个排列的视图之前或最后排列的视图之后的间距。因此,对于水平堆栈视图,要解决的问题是,包括两个零宽度视图(或垂直堆栈视图的零高度)。然后,当您在堆栈视图上使用均匀间距时,它还会显示所有已排列的子视图之前和之后的间距。

  4. NSLayoutAttributeCenterXmultiple另一项技术是为您的六个按钮定义attribute:NSLayoutAttributeCenterXattribute:NSLayoutAttributeCenterY属性,而不是使用constant值,使用multiplier字段。这种技术虽然有点简单,但并不总能呈现出所需的效果,所以我不会描述它,除非它是你绝对想要追求的东西。我已经在这里进入了tl:dr领域。

  5. 集合视图:另一种方法是使用UICollectionView,它可以优雅地处理此方案。它设计得很好,可以让你在网格中布局单元格。

  6. 硬编码值:为了完整起见,我会注意到您只需指定A,B,C和D的特定值(以及宽度和高度)约束)。您甚至不必担心设置E约束,而只需将中间两个的垂直中心约束设置为它们的超视图,并且您已经有效地完成了(因为E表示的间距应该是自然的结果前面的步骤,假设A = C且B = D)。如果要根据设备大小和/或方向调整这些值,则可以根据视图的大小实现viewWillLayoutSubviews来调整这些约束的常量。

答案 1 :(得分:2)

更新:我有一个更好的解决方案,不使用垫片。请查看here

好的,这可以在IB中很快实现。它太简单了。这是一个有助于说明的图表。 enter image description here

假设v1-6是你的按钮,s1-5是你的垫片。 1)在IB控制中拖出红线所示的所有连接。

2)移动单击v1-6和图钉图标(看起来像| -I- |)将宽度和高度设置为一个确定的值。另外,设置高度和宽度相等。

3)移位选择s1-4(不是5)并将高度设置为相等。不要给它一个明确的高度,因为这应该由系统计算。你可能还需要将s1-4的宽度设置为相等,但不要给它们一定的宽度。

4)控制从中心视图拖动到前缘和后缘并设置中心约束。

所以,你可能会想,好吧,现在应该可以了。它没有。这是我的应用程序以纵向运行,颜色略有不同。看起来不错。 (注意,一旦你进行了设置,你就会使垫片不可见。)

enter image description here

但是当我旋转时,哎呀!

enter image description here

这里发生了什么?一旦我们了解出了什么问题,问题就非常容易解决。我们想要的是让IB不要缩小我们的观点。我们希望IB能够使间隔物和空间在必要时缩小和增长,但只留下我们的观点。基本上,IB已经尽可能地缩小了间隔物的纵向,并试图使一切适合IB缩小了我们的观点。但我们希望IB缩小视图和间隔符之间的垂直空间,而不是我们的视图。解决方案非常简单。我们所要做的就是调整垂直空间的优先级,一切都很好。因此,选择IB中的垂直空间并将优先级调整为750.垂直间距线将显示为虚线。完成。

enter image description here

enter image description here

好的,所以这就是我们所期望的一切。

enter image description here

随着垫片明确:

enter image description here

enter image description here