在容器视图中均匀分隔多个视图

not*_*bob 273 rotation spacing ios autolayout ios6

自动布局让我的生活变得困难.从理论上讲,当我切换时它会非常有用,但我似乎总是在打架.

我做了一个演示项目试图找到帮助.有没有人知道如何在调整视图大小时使视图之间的间距均匀增加或减少?

这是三个标签(手动间隔垂直):

此搜索

我想要的是让他们在旋转时均匀地调整间距(而不是视图大小).默认情况下,顶视图和底视图朝中心方向挤压:

图像2

smi*_*Bot 312

看,没有间隔!

根据我原来答案评论部分的建议,特别是@Rivera的有用建议,我简化了原来的答案.

我正在使用GIF来说明这是多么简单.我希望你能找到有用的GIF.为了防止您遇到GIF问题,我在下面用简单的屏幕截图包含了旧答案.

说明:

1)添加按钮或标签.我正在使用3个按钮.

2)从每个按钮向superview添加一个中心x约束:

在此输入图像描述

3)从每个按钮添加约束到底部布局约束:

在此输入图像描述

4)调整上面#3中添加的约束如下:

a)选择约束, b)删除常量(设置为0), c)按如下方式更改乘数:取按钮数+ 1,从顶部开始,将乘数设置为buttonCountPlus1:1,然后按buttonCountPlus1 :2,最后是buttonCountPlus1:3.(如果你感兴趣,我会在下面的旧答案中解释我从哪里得到这个公式).

在此输入图像描述

5)这是一个运行的演示!

在此输入图像描述

注意:如果按钮的高度较大,则需要在常量值中对此进行补偿,因为约束来自按钮的底部.


老答案


尽管Apple的文档和Erica Sadun的优秀书籍(Auto Layout Demystified)所说,但是可以在没有间隔符的情况下均匀地观看视图.这在IB和代码中非常简单,可以平均分配任意数量的元素.您只需要一个称为"部分公式"的数学公式.它比解释更简单.我将通过在IB中展示它来尽力而为,但它在代码中也很容易.

在这个例子中,你会的

1)首先将每个标签设置为具有中心约束.这很简单.只需控制从每个标签拖动到底部.

2)按住shift,因为您可能还要添加我们将要使用的其他约束,即"底部空间到底部布局指南".

3)选择"底部空间到底部布局指南","水平居中容器".对所有3个标签执行此操作.

按住shift键为每个标签添加这两个约束

基本上,如果我们采用我们希望确定其坐标的标签并将其除以标签总数加1,那么我们可以添加一个数字以获得动态位置.我正在简化公式,但你可以用它同时设置水平间距或垂直和水平.它超级强大!

这是我们的乘数.

Label1 = 1/4 = .25,

Label2 = 2/4 = .5,

Label3 = 3/4 = .75

(编辑:@Rivera评论说你可以直接在乘数字段中使用比率,并使用xCode进行数学运算!)

4)所以,让我们选择Label1并选择底部约束.像这样: 在此输入图像描述

5)在Attributes Inspector中选择"Second Item".

6)从下拉列表中选择"反向第一和第二项".

7)将常量和wC hAny值清零.(如果需要,可以在这里添加偏移量).

8)这是关键部分:在乘数字段中添加第一个乘数0.25.

9)当你在它时,将顶部的"第一项"设置为"中心",因为我们希望将它居中到标签的y中心.这是所有应该看起来的样子.

在此输入图像描述

10)对每个标签重复此过程并插入相关乘数:Label2为0.5,Label3为0.75.这是所有紧凑型设备的最终产品!超级简单.我一直在寻找很多涉及大量代码和间隔器的解决方案.这是我在这个问题上看到的最好的解决方案.

更新:@kraftydevil补充说,底部布局指南仅出现在故事​​板中,而不是出现在xib中.在xib中使用'Bottom Space to Container'.接得好!

在此输入图像描述

  • 哦 - 同样值得注意的是Xcode 6中的IB支持比率乘数,所以你可以输入"1:4","2:5","3:4"等内容. (6认同)
  • @kraftydevil AFAIK底部布局指南仅出现在故事​​板中,而不是出现在xib中.在xib中使用'Bottom Space to Container'. (4认同)
  • 需要进行一些试验才能真正理解这里发生的事情,但到目前为止,这是我见过的最好的方法! (3认同)
  • 试图找出如何横向完成这个 - 比如从左边开始的第一个TextView 1/3,以及第二个TextView 2/3(其余部分)......(编辑)得到它 - 做的前1/3(左一)尾随空间到右边距,反向,零,像之前一样分配... (3认同)
  • 对于水平间距,只需将尾随约束设置为每个子视图的超视图,然后设置比率乘数,例如.5:1,5:2,5:3等从左向右移动. (3认同)
  • 我还在努力.我认为你必须使用Xcode 6,因为Xcode 5约束中没有'wC hAny'选项.当我按照您的说明操作时,所有子视图都会卡在顶部中心. (2认同)
  • 此解决方案仅适用于奇数个视图.请参阅下面的Mete答案,了解适用于空间奇数和偶数视图的公式. (2认同)

小智 207

所以我的方法允许你在界面构建器中执行此操作.您所做的是创建"间隔视图",您已将其设置为与高度相等.然后为标签添加顶部和底部约束(请参见屏幕截图).

在此输入图像描述

更具体地说,我对'Spacer View 1'有一个顶级约束,使用高于1000的高度约束和高度等于所有其他'spacer视图'的超视图.'Spacer View 4'对superview有一个底部空间约束.每个标签对其最近的"间隔视图"具有相应的顶部和底部约束.

注意:确保您的标签上没有额外的顶部/​​底部空间限制到superview; 只是那些'空间视图'.这将是令人满意的,因为顶部和底部约束分别在"空间视图1"和"间隔视图4"上.

Duh 1:我复制了我的视图,只是将它放在横向模式中,这样你就可以看到它有效了.

Duh 2:'spacer views'可能是透明的.

Duh 3:这种方法可以横向应用.

  • 这有效.事实上,间隔视图可以*隐藏*,它们仍然会产生正确的布局. (9认同)
  • 无需使用垫片.请参阅下面的答案. (2认同)

Met*_*ete 93

非常快速的Interface Builder解决方案:

对于在超视图中均匀分布的任意数量的视图,只需为每个水平布局提供"Align Center X to superview"约束,或者为垂直布局选择"Align Center Y superview",并将Multiplier设置为N:p(注意:一些可以有更好的运气p:N-见下文)

哪里

N = total number of views,和

p = position of the view including spaces

第一个位置是1,然后是一个空格,使下一个位置3,所以p成为一个系列[1,3,5,7,9,...].适用于任意数量的视图.

所以,如果你有3个空间视图,它看起来像这样:

如何在IB中均匀地传播视图的插图

编辑注意:选择N:p或p:N取决于对齐约束的关系顺序.如果"First Item"是Superview.Center,您可以使用p:N,而如果Superview.Center是"Second Item",您可以使用N:p.如果有疑问,只需尝试两个...... :-)

  • 这对我来说不是"按原样"我不得不反转乘数(例如,第一项中的3:1转换为1:3).如果它可以帮助任何人,那就扔掉它. (6认同)
  • 如果元素大小不一样怎么办?这种模式不会正常工作吗? (4认同)
  • 我不明白这个解决方案是怎么回事?屏幕边缘和外部元件之间的间隙与外部元件和中心元件之间的间隙不同? (2认同)

Glo*_*del 66

从iOS 9开始,Apple已经(期待已久)让这一切变得非常简单UIStackView.只需在Interface Builder中选择要包含的视图,然后选择编辑器 - >嵌入 - >堆栈视图.为堆栈视图设置适当的宽度/高度/边距约束,并确保将Distribution属性设置为"Equal spacing":

当然,如果您需要支持iOS 8或更低版本,则必须选择其他选项之一.

  • Awersome!正是我在寻找的!非常感谢! (3认同)

jrt*_*ton 50

我一直在乘坐过山车,喜欢自动布局和讨厌它.爱它的关键似乎是接受以下内容:

  1. 界面构建器的编辑和"有用的"自动创建约束对于除了最简单的情况之外的所有情况都是无用的
  2. 创建类别以简化常见操作可以节省生命,因为代码是如此重复和冗长.

也就是说,您尝试的并不简单,并且很难在界面构建器中实现.在代码中执行起来非常简单.此代码在viewDidLoad,创建和定位三个标签,如何询问它们:

// Create three labels, turning off the default constraints applied to views created in code
UILabel *label1 = [UILabel new];
label1.translatesAutoresizingMaskIntoConstraints = NO;
label1.text = @"Label 1";

UILabel *label2 = [UILabel new];
label2.translatesAutoresizingMaskIntoConstraints = NO;
label2.text = @"Label 2";

UILabel *label3 = [UILabel new];
label3.translatesAutoresizingMaskIntoConstraints = NO;
label3.text = @"Label 3";

// Add them all to the view
[self.view addSubview:label1];
[self.view addSubview:label2];
[self.view addSubview:label3];

// Center them all horizontally
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:label1 attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0]];

[self.view addConstraint:[NSLayoutConstraint constraintWithItem:label2 attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0]];

[self.view addConstraint:[NSLayoutConstraint constraintWithItem:label3 attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0]];

// Center the middle one vertically
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:label2 attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterY multiplier:1.0 constant:0]];

// Position the top one half way up
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:label1 attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:label2 attribute:NSLayoutAttributeCenterY multiplier:0.5 constant:0]];

// Position the bottom one half way down
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:label3 attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:label2 attribute:NSLayoutAttributeCenterY multiplier:1.5 constant:0]];
Run Code Online (Sandbox Code Playgroud)

正如我所说,这个代码在几个类别方法中大大简化了UIView,但为了清楚起见,我已经完成了很长的路要走.

类别是这里对于那些有兴趣,并且其具有用于沿特定轴均匀间隔的视图的阵列的方法.


Ben*_*man 20

大多数这些解决方案都依赖于奇数个项目,因此您可以将中间项目放在中间位置.如果您仍然希望均匀分配偶数项目,该怎么办?这是一个更通用的解决方案.此类别将沿垂直轴或水平轴均匀分布任意数量的项目.

在superview中垂直分布4个标签的示例用法:

[self.view addConstraints:
     [NSLayoutConstraint constraintsForEvenDistributionOfItems:@[label1, label2, label3, label4]
                                        relativeToCenterOfItem:self.view
                                                    vertically:YES]];
Run Code Online (Sandbox Code Playgroud)

NSLayoutConstraint + EvenDistribution.h

@interface NSLayoutConstraint (EvenDistribution)

/**
 * Returns constraints that will cause a set of views to be evenly distributed horizontally
 * or vertically relative to the center of another item. This is used to maintain an even
 * distribution of subviews even when the superview is resized.
 */
+ (NSArray *) constraintsForEvenDistributionOfItems:(NSArray *)views
                             relativeToCenterOfItem:(id)toView
                                         vertically:(BOOL)vertically;

@end
Run Code Online (Sandbox Code Playgroud)

NSLayoutConstraint + EvenDistribution.m

@implementation NSLayoutConstraint (EvenDistribution)

+(NSArray *)constraintsForEvenDistributionOfItems:(NSArray *)views
                           relativeToCenterOfItem:(id)toView vertically:(BOOL)vertically
{
    NSMutableArray *constraints = [NSMutableArray new];
    NSLayoutAttribute attr = vertically ? NSLayoutAttributeCenterY : NSLayoutAttributeCenterX;

    for (NSUInteger i = 0; i < [views count]; i++) {
        id view = views[i];
        CGFloat multiplier = (2*i + 2) / (CGFloat)([views count] + 1);
        NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:view
                                                                      attribute:attr
                                                                      relatedBy:NSLayoutRelationEqual
                                                                         toItem:toView
                                                                      attribute:attr
                                                                     multiplier:multiplier
                                                                       constant:0];
        [constraints addObject:constraint];
    }

    return constraints;
}

@end
Run Code Online (Sandbox Code Playgroud)


smi*_*org 17

查看开源库PureLayout.它提供了一些用于分发视图的API方法,包括每个视图之间的间距固定的视图(视图大小根据需要变化),以及每个视图的大小固定的位置(视图之间的间距根据需要而变化).请注意,所有这些都是在不使用任何"间隔视图"的情况下完成的.

来自NSArray + PureLayout.h:

// NSArray+PureLayout.h

// ...

/** Distributes the views in this array equally along the selected axis in their superview. Views will be the same size (variable) in the dimension along the axis and will have spacing (fixed) between them. */
- (NSArray *)autoDistributeViewsAlongAxis:(ALAxis)axis
                                alignedTo:(ALAttribute)alignment
                         withFixedSpacing:(CGFloat)spacing;

/** Distributes the views in this array equally along the selected axis in their superview. Views will be the same size (fixed) in the dimension along the axis and will have spacing (variable) between them. */
- (NSArray *)autoDistributeViewsAlongAxis:(ALAxis)axis
                                alignedTo:(ALAttribute)alignment
                            withFixedSize:(CGFloat)size;

// ...
Run Code Online (Sandbox Code Playgroud)

由于它是全部开源的,如果您有兴趣了解如何在没有间隔视图的情况下实现这一点,只需看一下实现.(这取决于利用constant 和 multiplier约束.)


Ole*_*nov 17

正确和最简单的方法是使用堆栈视图.

  1. 将标签/视图添加到堆栈视图:

在此输入图像描述

  1. 选择Stack View并将Distribution设置为Equal Spacing:

在此输入图像描述

  1. 将间距添加到堆栈视图的最近邻居约束并更新帧:

在此输入图像描述

  1. 将高度限制添加到所有标签:

在此输入图像描述

  1. 享受预览:

在此输入图像描述

  • 这仅是&gt; = iOS 9.0,因此在开始实施之前请检查您的部署目标:)很好的是,它已经添加了! (2认同)
  • 2018 现在,使用堆栈视图 (2认同)

Flo*_*ian 9

我遇到了类似的问题并发现了这篇文章.但是,当前提供的答案都没有以您希望的方式解决问题.它们不会使间距相等,而是平均分配标签的中心.重要的是要明白这是不一样的.我构建了一个小图来说明这一点.

查看间距图

共有3个视图,全部高20pt.使用任何建议的方法均匀分布视图的中心并为您提供图示的布局.请注意,视图的y中心间隔相等.但是,superview和顶视图之间的间距是15pt,而子视图之间的间距只有5pt.为了使视图间隔均匀,这些视图应均为10pt,即所有蓝色箭头应为10pt.

尽管如此,我还没有想出一个好的通用解决方案.目前我最好的想法是在子视图之间插入"间距视图",并将间距视图的高度设置为相等.


hay*_*esk 8

我完全可以在IB中解决这个问题:

  1. 制定约束以将每个子视图的中心Y与超视图的下边缘对齐.
  2. 将每个约束的乘数设置为1/2n,3/2n,5/2n,...,n-1/2n,其中n是您要分发的子视图的数量.

因此,如果您有三个标签,请将每个约束的乘数设置为0.1666667,0.5,0.833333.


Owe*_*rey 5

我发现了一种完美而简单的方法.自动布局不允许您平均调整空间大小,但它允许您平均调整视图大小.只需在字段之间放置一些不可见的视图,并告诉自动布局以保持它们的大小相同.它完美无缺!

初始XIB

拉伸XIB

但有一点需要注意; 当我缩小界面设计器的大小时,有时它会混淆并留下标签,如果大小改变了奇数,就会产生冲突.否则它完美无缺.

编辑:我发现冲突成了问题.因此,我采用了一个间距约束,将其删除并用两个约束替换它,大于或等于和小于或等于.两者的大小相同,优先级低于其他约束.结果是没有进一步的冲突.