ChatGPT解决这个技术问题 Extra ChatGPT

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

自动布局使我的生活变得困难。理论上,当我切换时它会非常有用,但我似乎一直在与它作斗争。

我做了一个演示项目来尝试寻求帮助。有谁知道如何在调整视图大小时使视图之间的空间均匀增加或减少?

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

https://i.stack.imgur.com/rc7LK.png

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

https://i.stack.imgur.com/APdX9.png

也许将约束从一个标签设置到另一个标签,并将它们设置为“大于或等于”的关系会有所帮助
以编程方式例如使用 NSLayoutConstraint 的这种方法:+ (id)constraintWithItem:(id)view1 属性:(NSLayoutAttribute)attr1 relatedBy:(NSLayoutRelation)relation toItem:(id)view2 属性:(NSLayoutAttribute)attr2 multiplier:(CGFloat)multiplier常数:(CGFloat)c
我开源了一个通用的 UITabBar 替代品,它使用 Auto Layout 推广了这种方法。您可以查看测试以了解我如何生成自动布局约束。 GGTabBar

S
SmileBot

看,没有间隔!

根据我原始答案的评论部分中的建议,尤其是@Rivera 的有用建议,我简化了我的原始答案。

我正在使用 gif 来说明这是多么简单。我希望你觉得这些 GIF 很有帮助。以防万一您对 gif 文件有疑问,我在下面的旧答案中包含了纯屏幕截图。

指示:

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

2)将每个按钮的中心x约束添加到超级视图:

https://i.stack.imgur.com/s4utU.gif

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

https://i.stack.imgur.com/NrSmj.gif

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

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

https://i.stack.imgur.com/BIIi9.gif

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

https://i.stack.imgur.com/6AfaH.gif

注意:如果您的按钮具有较大的高度,那么您将需要在常量值中对此进行补偿,因为约束来自按钮的底部。

旧答案

尽管 Apple 的文档和 Erica Sadun 的优秀书籍(Auto Layout Demystified)说了什么,但可以在没有间隔的情况下均匀地分隔视图。这在 IB 和代码中非常简单,可以用于您希望均匀分布的任意数量的元素。您所需要的只是一个称为“截面公式”的数学公式。做起来比解释要简单。我会尽力在 IB 中演示它,但在代码中也很容易做到。

在有问题的示例中,您将

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

2) 按住 shift 键,因为您不妨添加我们将要使用的另一个约束,即“底部空间到底部布局指南”。

3)选择“底部空间到底部布局指南”和“在容器中水平居中”。对所有 3 个标签执行此操作。

https://i.stack.imgur.com/HglaO.png

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

这是我们的乘数。

标签1 = 1/4 = .25,

标签2 = 2/4 = .5,

标签3 = 3/4 = .75

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

https://i.stack.imgur.com/LA7X5.png

5)在属性检查器中选择“第二项”。

6) 从下拉列表中选择“反转第一项和第二项”。

7) 将常数和 wC hAny 值清零。 (如果需要,可以在此处添加偏移量)。

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

9)当你在它设置顶部的“第一项”为“CenterY”,因为我们想将它居中到标签的 y 中心。这就是所有应该看起来的样子。

https://i.stack.imgur.com/sxtat.png

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

更新:@kraftydevil 补充说底部布局指南仅出现在故事板中,而不出现在 xibs 中。在 xibs 中使用“底部空间到容器”。接得好!

https://i.stack.imgur.com/5SQa4.png


我仍在为此苦苦挣扎。我认为您必须使用 Xcode 6,因为 Xcode 5 约束中没有“wC hAny”选项。当我按照您的指示进行操作时,所有子视图都会卡在顶部中心。
@kraftydevil AFAIK 底部布局指南仅出现在情节提要中,而不出现在 xibs 中。在 xibs 中使用“底部空间到容器”。
哦——还值得注意的是,Xcode 6 中的 IB 支持比率乘数,因此您可以输入“1:4”、“2:5”、“3:4”等内容。
试图弄清楚如何水平地做到这一点 - 就像从左边开始的第一个 TextView 1/3,以及第二个 TextView 2/3(剩下的方式)......(编辑)明白了 - 做第一个 1/3(左一个)尾随空格到右边距,反向,零,像以前一样分配......
对于水平间距,只需为每个子视图设置超级视图的尾随约束,然后设置比率乘数,例如。 5:1、5:2、5:3 等从左到右移动。
S
Spencer Hall

因此,我的方法允许您在界面生成器中执行此操作。您所做的是创建您已设置为同等匹配高度的“间隔视图”。然后将顶部和底部约束添加到标签(参见屏幕截图)。

https://i.stack.imgur.com/bJOix.png

更具体地说,我对“Spacer View 1”有一个最高约束,以使用低于 1000 的优先级和高度等于所有其他“间隔视图”的高度约束来超级视图。 “Spacer View 4”对超级视图有底部空间限制。每个标签对其最近的“间隔视图”都有各自的顶部和底部约束。

注意:确保您的标签上没有额外的顶部/底部空间限制以进行超级查看;只是“空间视图”的那些。这将是可以满足的,因为顶部和底部约束分别在“Space View 1”和“Spacer View 4”上。

Duh 1:我复制了我的视图,只是将其置于横向模式,以便您可以看到它有效。

Duh 2:“间隔视图”可能是透明的。

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


这行得通。事实上,间隔视图可以隐藏,它们仍然会产生正确的布局。
这非常有帮助。正如关于仅将间隔视图标记为隐藏的评论一样。然后你仍然可以在你的故事板/xib 中看到它们,但它们不会出现在你的应用程序中。非常好。
经过几个小时的反复尝试,我几乎成功了。不幸的是,Xcode 不断删除我的 top-space-to-button 和 bottom-space 约束,打破了按钮和垫片之间的链,并用无用的任意 top-space-to-superview 约束替换它们。
同样的方法在水平布局中适用于我 - 我有固定宽度的视图,由等宽的间隔视图分隔。太好了,我不需要将它与任何代码混合。谢谢!
无需使用垫片。请看下面我的回答。
M
Mete

非常快速的界面生成器解决方案:

对于要在超级视图中均匀分布的任意数量的视图,只需为水平布局给每个“对齐中心 X 到超级视图”约束,或为垂直布局设置“对齐中心 Y 超级视图”,并将乘数设置为 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 个视图要留出空间,它看起来像这样:

https://i.stack.imgur.com/l1175.jpg

编辑 注意:选择 N:pp:N 取决于对齐约束的关系顺序。如果“First Item”是Superview.Center,则可以使用p:N,而如果Superview.Center 是“Second Item”,则可以使用N:p。如有疑问,请尝试两者... :-)


如果您切换到另一种语言,此解决方案将不会反映设计
如果元素大小不同怎么办?这种模式不能正常工作吗?
我不明白这个解决方案如何正确?屏幕边缘和外部元素之间的间隙与外部元素和中心元素之间的间隙不同吗?
这对我来说不是“按原样”我必须反转乘数(例如,第一项的 3:1 转换为 1:3)。如果它对任何人有帮助,就把它扔在那里。
感谢您的精彩回答,在 iOS10 上运行良好。是的,仅供参考,我有4个按钮。我使用的比例是:1/4、3/4、5/4、7/4。奇迹般有效!我很惊讶苹果如何让 UI 的一切变得如此复杂,哈哈。
G
Glorfindel

从 iOS 9 开始,Apple 使用(期待已久的)UIStackView 使这变得非常简单。只需选择要包含在 Interface Builder 中的视图,然后选择 Editor ->嵌入 ->堆栈视图。为堆栈视图设置适当的宽度/高度/边距约束,并确保将 Distribution 属性设置为“等间距”:

https://i.stack.imgur.com/DnKFf.png

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


是的,很遗憾这没有复古兼容性,所以在您的应用需要支持 IOS8 之前,@Mete 响应是目前最好的。
j
jrturton

我一直在喜欢自动布局并讨厌它的过山车。爱它的关键似乎是接受以下几点:

界面构建器的编辑和“有用的”自动创建约束对所有人来说几乎是无用的,但最微不足道的情况除外 创建类别来简化常见操作是一种救命稻草,因为代码是如此重复和冗长。

也就是说,您所尝试的并不简单,并且很难在界面构建器中实现。在代码中执行非常简单。此代码在 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]];

正如我所说,这段代码通过 UIView 中的几个类别方法大大简化了,但为了清楚起见,我在这里做了很长的路要走。

对于感兴趣的人,该类别是 here,它具有沿特定轴均匀分布一组视图的方法。


先生,您是救生员。直到现在我才明白#1。界面生成器让我发疯,但我认为它能够做所有相同的事情。无论如何,我更喜欢使用代码,所以这是完美的,我会正确使用类别方法。
虽然绝对非常接近,但这并不能完全解决所提出的确切问题(保持视图大小相同,子视图之间的间距均匀)。 This solution 是精炼的一般情况答案。
O
Oleh Kudinov

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

将您的标签/视图添加到堆栈视图:

https://i.stack.imgur.com/tC2wM.jpg

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

https://i.stack.imgur.com/78eRY.jpg

将 Spacing 添加到 Stack View 的最近邻约束并更新帧:

https://i.stack.imgur.com/Bvupl.jpg

为所有标签添加高度约束(可选)。仅对于没有固有大小的视图才需要)。例如,标签在这里不需要高度约束,例如只需要设置 numberOfLines = 3 或 0。

https://i.stack.imgur.com/eqtaU.jpg

享受预览:

https://i.stack.imgur.com/D8eDh.jpg


这只是> = iOS 9.0,所以在开始实施之前检查您的部署目标:) 很高兴看到它已被添加!
2018 现在,使用堆栈视图
B
Ben Dolman

这些解决方案中的大多数都依赖于奇数个项目,以便您可以取中间项目并将其居中。如果您有偶数个项目但仍希望平均分配怎么办?这是一个更通用的解决方案。此类别将沿垂直或水平轴均匀分布任意数量的项目。

在其超级视图中垂直分布 4 个标签的示例用法:

[self.view addConstraints:
     [NSLayoutConstraint constraintsForEvenDistributionOfItems:@[label1, label2, label3, label4]
                                        relativeToCenterOfItem:self.view
                                                    vertically:YES]];

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

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

它的工作原理是删除所有约束,然后立即将宽度和高度约束添加到这些对象,然后调用方法 constraintsForEvenDistributionOfItems:relativeToCenterOfItem:vertically:
@carlos_ms 我很想看到您的代码,因为当我尝试使用偶数个项目时,此代码在切换设备方向时可以完美运行。您确定您不会无意中遇到导致冲突的其他一些约束(例如自动调整大小约束)吗?
下面是创建 4 个标签并沿垂直轴均匀分布它们的示例:gist.github.com/bdolman/5379465
s
smileyborg

查看开源库 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;

// ...

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


干得好!尽管您可能应该重命名 repo,以便可以通过 cocoapods 使其可用。
F
Florian

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

https://i.stack.imgur.com/hnHLR.png

有 3 个视图,全部为 20pt 高。使用任何建议的方法均等地分布视图的中心并为您提供图示的布局。请注意,视图的 y 中心是等距的。然而,superview 和 top view 之间的间距是 15pt,而 subview 之间的间距只有 5pt。要使视图等距分布,它们都应为 10pt,即所有蓝色箭头应为 10pt。

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


我使用了隐藏间隔视图的解决方案,效果很好。
J
Jason Moore

我能够在 IB 中完全解决这个问题:

进行约束以将每个子视图的中心 Y 与父视图的底部边缘对齐。将每个约束的乘数设置为 1/2n、3/2n、5/2n、...、n-1/2n,其中 n 是您正在分发的子视图的数量。

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


我实际上不得不做 1/n 3/n 5/n 7/n 到 (2n-1)/n
O
Owen Godfrey

我找到了一个完美而简单的方法。自动布局不允许您平等地调整空间大小,但它允许您平等地调整视图大小。只需在您的字段之间放置一些不可见的视图,并告诉自动布局保持它们相同的大小。它完美地工作!

https://i.stack.imgur.com/vuYgl.png

https://i.stack.imgur.com/EeRNV.png

不过要注意一件事;当我在界面设计器中减小尺寸时,有时它会感到困惑并在原来的位置留下一个标签,如果尺寸更改为奇数,它就会发生冲突。否则它工作得很好。

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


R
Ray W

基于 Ben Dolman 的回答,这可以更均匀地分布视图(使用填充等):

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

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

    return constraints;
}

M
Mehul Thakkar

检查 https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/AutolayoutPG/AutoLayoutbyExample/AutoLayoutbyExample.html 对解决您的问题有很好的描述。


在 iOS 9 发布后,将 UIStackView 作为执行此任务的最佳选择,Apple 已删除此页面
J
Johannes

使用标签至少可以正常工作:

@"H:|-15-[first(==second)]-[second(==third)]-[third(==first)]-15-|

如果第一个与第二个具有相同的宽度,第二个与第三个具有相同的宽度,第三个与第一个具有相同的宽度,那么它们都将具有相同的宽度……您可以水平(H)和垂直(V)。


S
Sarath Raveendran

迅捷3版

let _redView = UIView()
        _redView.backgroundColor = UIColor.red
        _redView.translatesAutoresizingMaskIntoConstraints = false

        let _yellowView = UIView()
        _yellowView.backgroundColor = UIColor.yellow
        _yellowView.translatesAutoresizingMaskIntoConstraints = false

        let _blueView = UIView()
        _blueView.backgroundColor = UIColor.blue
        _blueView.translatesAutoresizingMaskIntoConstraints = false

        self.view.addSubview(_redView)
        self.view.addSubview(_yellowView)
        self.view.addSubview(_blueView)

        var views = ["_redView": _redView, "_yellowView": _yellowView, "_blueView":_blueView]

        var nslayoutConstraint_H = NSLayoutConstraint.constraints(withVisualFormat: "|->=0-[_redView(40)]->=0-[_yellowView(40)]->=0-[_blueView(40)]->=0-|", options: [.alignAllTop, .alignAllBottom], metrics: nil, views: views)
        self.view.addConstraints(nslayoutConstraint_H)

        var nslayoutConstraint_V = NSLayoutConstraint.constraints(withVisualFormat: "V:[_redView(60)]", options: NSLayoutFormatOptions.init(rawValue: 0), metrics: nil, views: views)
        self.view.addConstraints(nslayoutConstraint_V)


        let constraint_red = NSLayoutConstraint.init(item: self.view, attribute: .centerY, relatedBy: .equal, toItem: _redView, attribute: .centerY, multiplier: 1, constant: 0)
        self.view.addConstraint(constraint_red)

        let constraint_yellow = NSLayoutConstraint.init(item: self.view, attribute: .centerX, relatedBy: .equal, toItem: _yellowView, attribute: .centerX, multiplier: 1, constant: 0)
        self.view.addConstraint(constraint_yellow)

        let constraint_yellow1 = NSLayoutConstraint.init(item: _redView, attribute: .centerX, relatedBy: .equal, toItem: _yellowView, attribute: .leading, multiplier: 0.5, constant: 0)
        self.view.addConstraint(constraint_yellow1)

        let constraint_yellow2 = NSLayoutConstraint.init(item: _blueView, attribute: .centerX, relatedBy: .equal, toItem: _yellowView, attribute: .leading, multiplier: 1.5, constant: 40)
        self.view.addConstraint(constraint_yellow2)

详细说明此代码如何回答问题将有助于未来的访问者。
M
Marcal

我知道距离第一个答案已经有一段时间了,但我刚刚遇到了同样的问题,我想分享我的解决方案。为子孙后代...

我在 viewDidLoad 上设置了我的观点:

- (void)viewDidLoad {

    [super viewDidLoad];

    cancelButton = [UIButton buttonWithType: UIButtonTypeRoundedRect];
    cancelButton.translatesAutoresizingMaskIntoConstraints = NO;
    [cancelButton setTitle:@"Cancel" forState:UIControlStateNormal];
    [self.view addSubview:cancelButton];

    middleButton = [UIButton buttonWithType: UIButtonTypeRoundedRect];
    middleButton.translatesAutoresizingMaskIntoConstraints = NO;
    [middleButton setTitle:@"Middle" forState:UIControlStateNormal];
    [self.view addSubview:middleButton];

    nextButton = [UIButton buttonWithType: UIButtonTypeRoundedRect];
    nextButton.translatesAutoresizingMaskIntoConstraints = NO;
    [nextButton setTitle:@"Next" forState:UIControlStateNormal];
    [self.view addSubview:nextButton];


    [self.view setNeedsUpdateConstraints];

}

然后,在 updateViewConstrains 上,首先删除所有约束,然后创建视图字典,然后计算要在视图之间使用的空间。之后,我只使用 Visual Language Format 来设置约束:

- (void)updateViewConstraints {


    [super updateViewConstraints];

    [self.view removeConstraints:self.view.constraints];

    NSDictionary *viewsDictionary = NSDictionaryOfVariableBindings(cancelButton, nextButton, middleButton);

    float distance=(self.view.bounds.size.width-cancelButton.intrinsicContentSize.width-nextButton.intrinsicContentSize.width-middleButton.intrinsicContentSize.width-20-20)/  ([viewsDictionary count]-1);  // 2 times 20 counts for the left & rigth margins
    NSNumber *distancies=[NSNumber numberWithFloat:distance];

//    NSLog(@"Distancies: %@", distancies);
//    
//    NSLog(@"View Width: %f", self.view.bounds.size.width);
//    NSLog(@"Cancel Width: %f", cancelButton.intrinsicContentSize.width);
//    NSLog(@"Middle Width: %f", middleButton.intrinsicContentSize.width);
//    NSLog(@"Next Width: %f", nextButton.intrinsicContentSize.width);



    NSArray *constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"|-[cancelButton]-dis-[middleButton]-dis-[nextButton]-|"
                                                                   options:NSLayoutFormatAlignAllBaseline
                                                                   metrics:@{@"dis":distancies}
                                                                     views:viewsDictionary];


    [self.view addConstraints:constraints];



    constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"V:[nextButton]-|"
                                                          options:0
                                                          metrics:nil
                                                            views:viewsDictionary];
    [self.view addConstraints:constraints];



}

这种方法的好处是你只需要做很少的数学运算。我并不是说这是完美的解决方案,但我为我试图实现的布局工作。

我希望它有所帮助。


e
easeout

这是一个将任意数量的子视图垂直居中的解决方案,即使它们具有唯一的大小。您要做的是制作一个中级容器,将其置于超级视图的中心,然后将所有子视图放入容器中并相互排列。但至关重要的是,您还需要将它们限制在容器的顶部和底部,以便容器可以正确调整大小并在超级视图中居中。通过从其子视图中计算出正确的高度,容器可以垂直居中。

在此示例中,self 是您将所有子视图居中的超级视图。

NSArray *subviews = @[ (your subviews in top-to-bottom order) ];

UIView *container = [[UIView alloc] initWithFrame:CGRectZero];
container.translatesAutoresizingMaskIntoConstraints = NO;
for (UIView *subview in subviews) {
    subview.translatesAutoresizingMaskIntoConstraints = NO;
    [container addSubview:subview];
}
[self addSubview:container];

[self addConstraint:[NSLayoutConstraint constraintWithItem:container attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual
                                                    toItem:self attribute:NSLayoutAttributeLeft multiplier:1.0f constant:0.0f]];
[self addConstraint:[NSLayoutConstraint constraintWithItem:container attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual
                                                    toItem:self attribute:NSLayoutAttributeRight multiplier:1.0f constant:0.0f]];
[self addConstraint:[NSLayoutConstraint constraintWithItem:container attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual
                                                    toItem:self attribute:NSLayoutAttributeCenterY multiplier:1.0f constant:0.0f]];

if (0 < subviews.count) {
    UIView *firstSubview = subviews[0];
    [container addConstraint:[NSLayoutConstraint constraintWithItem:firstSubview attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual
                                                             toItem:container attribute:NSLayoutAttributeTop multiplier:1.0f constant:0.0f]];
    UIView *lastSubview = subviews.lastObject;
    [container addConstraint:[NSLayoutConstraint constraintWithItem:lastSubview attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual
                                                             toItem:container attribute:NSLayoutAttributeBottom multiplier:1.0f constant:0.0f]];

    UIView *subviewAbove = nil;
    for (UIView *subview in subviews) {
        [container addConstraint:[NSLayoutConstraint constraintWithItem:subview attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual
                                                                 toItem:container attribute:NSLayoutAttributeCenterX multiplier:1.0f constant:0.0f]];
        if (subviewAbove) {
            [container addConstraint:[NSLayoutConstraint constraintWithItem:subview attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual
                                                                     toItem:subviewAbove attribute:NSLayoutAttributeBottom multiplier:1.0f constant:10.0f]];
        }
        subviewAbove = subview;
    }
}

当使用必须居中的不同大小的视图时,这是最好的解决方案。
u
ucangetit

我刚刚使用乘数功能解决了我的问题。我不确定它是否适用于所有情况,但对我来说效果很好。我在 Xcode 6.3 仅供参考。

我最终做的是:

1) 首先将我的按钮放置在 320px 宽度的屏幕上,按照我希望它在 320px 设备上的显示方式分布。

https://i.stack.imgur.com/znRFu.png

2)然后我在所有按钮的超级视图中添加了一个领先的空间约束。

https://i.stack.imgur.com/Yh14k.png

3) 然后我修改了前导空格的属性,使常数为 0,乘数为 x 偏移除以屏幕宽度(例如,我的第一个按钮距离左边缘 8px,所以我将乘数设置为 8/320)

4)那么这里重要的一步就是将约束关系中的第二个Item改为superview.Trailing而不是superview.leading。这是关键,因为 superview.Leading 为 0,在我的情况下为 320,因此 8/320 在 320px 设备上为 8 px,然后当 superview 的宽度更改为 640 或其他任何值时,视图都以相对于宽度的比例移动320px 的屏幕尺寸。这里的数学更容易理解。

https://i.stack.imgur.com/u86IK.png


z
zgjie

许多答案不正确,但得到很多计数。这里我只是以编程方式编写了一个解决方案,三个视图是水平对齐的,没有使用间隔视图,但它只有在故事板中使用时知道标签的宽度时才有效。

NSDictionary *views = NSDictionaryOfVariableBindings(_redView, _yellowView, _blueView);

[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"|->=0-[_redView(40)]->=0-[_yellowView(40)]->=0-[_blueView(40)]->=0-|" options:NSLayoutFormatAlignAllTop | NSLayoutFormatAlignAllBottom metrics:nil views:views]];

[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[_redView(60)]" options:0 metrics:nil views:views]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.view attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:_redView attribute:NSLayoutAttributeCenterY multiplier:1 constant:0]];

[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.view attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:_yellowView attribute:NSLayoutAttributeCenterX multiplier:1 constant:0]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:_redView attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:_yellowView attribute:NSLayoutAttributeLeading multiplier:0.5 constant:0]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:_blueView attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:_yellowView attribute:NSLayoutAttributeLeading multiplier:1.5 constant:40]];

S
Sandeep

这是另一个答案。我正在回答一个类似的问题,并看到引用此问题的链接。我没有看到任何类似于我的答案。所以,我想把它写在这里。

  class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = UIColor.whiteColor()
        setupViews()
    }

    var constraints: [NSLayoutConstraint] = []

    func setupViews() {

        let container1 = createButtonContainer(withButtonTitle: "Button 1")
        let container2 = createButtonContainer(withButtonTitle: "Button 2")
        let container3 = createButtonContainer(withButtonTitle: "Button 3")
        let container4 = createButtonContainer(withButtonTitle: "Button 4")

        view.addSubview(container1)
        view.addSubview(container2)
        view.addSubview(container3)
        view.addSubview(container4)

        [

            // left right alignment
            container1.leftAnchor.constraintEqualToAnchor(view.leftAnchor, constant: 20),
            container1.rightAnchor.constraintEqualToAnchor(view.rightAnchor, constant: -20),
            container2.leftAnchor.constraintEqualToAnchor(container1.leftAnchor),
            container2.rightAnchor.constraintEqualToAnchor(container1.rightAnchor),
            container3.leftAnchor.constraintEqualToAnchor(container1.leftAnchor),
            container3.rightAnchor.constraintEqualToAnchor(container1.rightAnchor),
            container4.leftAnchor.constraintEqualToAnchor(container1.leftAnchor),
            container4.rightAnchor.constraintEqualToAnchor(container1.rightAnchor),


            // place containers one after another vertically
            container1.topAnchor.constraintEqualToAnchor(view.topAnchor),
            container2.topAnchor.constraintEqualToAnchor(container1.bottomAnchor),
            container3.topAnchor.constraintEqualToAnchor(container2.bottomAnchor),
            container4.topAnchor.constraintEqualToAnchor(container3.bottomAnchor),
            container4.bottomAnchor.constraintEqualToAnchor(view.bottomAnchor),


            // container height constraints
            container2.heightAnchor.constraintEqualToAnchor(container1.heightAnchor),
            container3.heightAnchor.constraintEqualToAnchor(container1.heightAnchor),
            container4.heightAnchor.constraintEqualToAnchor(container1.heightAnchor)
            ]
            .forEach { $0.active = true }
    }


    func createButtonContainer(withButtonTitle title: String) -> UIView {
        let view = UIView(frame: .zero)
        view.translatesAutoresizingMaskIntoConstraints = false

        let button = UIButton(type: .System)
        button.translatesAutoresizingMaskIntoConstraints = false
        button.setTitle(title, forState: .Normal)
        view.addSubview(button)

        [button.centerYAnchor.constraintEqualToAnchor(view.centerYAnchor),
            button.leftAnchor.constraintEqualToAnchor(view.leftAnchor),
            button.rightAnchor.constraintEqualToAnchor(view.rightAnchor)].forEach { $0.active = true }

        return view
    }
}

https://i.stack.imgur.com/lpbA9.png

同样,这也可以通过 iOS9 UIStackViews 轻松完成。

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = UIColor.greenColor()
        setupViews()
    }

    var constraints: [NSLayoutConstraint] = []

    func setupViews() {

        let container1 = createButtonContainer(withButtonTitle: "Button 1")
        let container2 = createButtonContainer(withButtonTitle: "Button 2")
        let container3 = createButtonContainer(withButtonTitle: "Button 3")
        let container4 = createButtonContainer(withButtonTitle: "Button 4")

        let stackView = UIStackView(arrangedSubviews: [container1, container2, container3, container4])
        stackView.translatesAutoresizingMaskIntoConstraints = false
        stackView.axis = .Vertical
        stackView.distribution = .FillEqually
        view.addSubview(stackView)

        [stackView.topAnchor.constraintEqualToAnchor(view.topAnchor),
            stackView.bottomAnchor.constraintEqualToAnchor(view.bottomAnchor),
            stackView.leftAnchor.constraintEqualToAnchor(view.leftAnchor, constant: 20),
            stackView.rightAnchor.constraintEqualToAnchor(view.rightAnchor, constant: -20)].forEach { $0.active = true }
    }


    func createButtonContainer(withButtonTitle title: String) -> UIView {
        let button = UIButton(type: .Custom)
        button.translatesAutoresizingMaskIntoConstraints = false
        button.backgroundColor = UIColor.redColor()
        button.setTitleColor(UIColor.whiteColor(), forState: .Normal)
        button.setTitle(title, forState: .Normal)
        let buttonContainer = UIStackView(arrangedSubviews: [button])
        buttonContainer.distribution = .EqualCentering
        buttonContainer.alignment = .Center
        buttonContainer.translatesAutoresizingMaskIntoConstraints = false
        return buttonContainer
    }
}

请注意,它与上述方法完全相同。它添加了四个容器视图,它们被平均填充,并且一个视图被添加到每个中心对齐的堆栈视图中。但是,这个版本的 UIStackView 减少了一些代码并且看起来不错。


C
Colin

另一种方法可能是让顶部和底部标签分别具有相对于视图顶部和底部的约束,并且让中间视图分别具有相对于第一和第三视图的顶部和底部约束。

请注意,您对约束的控制比通过将视图彼此靠近拖动直到出现引导虚线来实现的控制更多 - 这些表示将形成的两个对象之间的约束,而不是对象和父视图之间的约束。

在这种情况下,您可能希望将约束更改为“大于或等于”所需值,而不是“等于”以允许它们调整大小。不确定这是否会完全符合您的要求。


s
sust86

在 InterfaceBuilder 中解决这个问题的非常简单的方法:

将居中标签(label2)设置为“Horizontal Center in Container”和“Vertical Center in Container”

选择居中标签和顶部标签 (label1 + label2) 并为垂直间距添加两个约束。一个大于或等于最小间距。一个小于或等于最大间距。

居中标签和底部标签 (label2 + label3) 相同。

此外,您还可以向 label1 添加两个约束 - 到 SuperView 的顶部空间和到 label2 的两个约束 - 到 SuperView 的底部空间。

结果将是所有 4 个间距都将同样地改变它们的大小。


我发现这仅在您调整超级视图的大小以使间距恰好取最小值或最大值时才有效。当您将其大小调整为介于两者之间的某个值时,子视图不会均匀分布。
p
penumbra

我做了一个可能有帮助的功能。此用法示例:

 [self.view addConstraints: [NSLayoutConstraint fluidConstraintWithItems:NSDictionaryOfVariableBindings(button1, button2, button3)
                                                                asString:@[@"button1", @"button2", @"button3"]
                                                               alignAxis:@"V"
                                                          verticalMargin:100
                                                        horizontalMargin:50
                                                             innerMargin:25]];

将导致 vertical distribution (抱歉没有 10 名嵌入图像)。如果您更改轴和一些边距值:

alignAxis:@"H"
verticalMargin:120
horizontalMargin:20
innerMargin:10

你会得到那个horizontal distribution

我是 iOS 的新手,但瞧!

均匀分布.h

@interface NSLayoutConstraint (EvenDistribution)

/**
 * Returns constraints that will cause a set of subviews
 * to be evenly distributed along an axis.
 */
+ (NSArray *)  fluidConstraintWithItems:(NSDictionary *) views
                               asString:(NSArray *) stringViews
                              alignAxis:(NSString *) axis
                         verticalMargin:(NSUInteger) vMargin
                       horizontalMargin:(NSUInteger) hMargin
                            innerMargin:(NSUInteger) inner;
@end

均匀分布.m

#import "EvenDistribution.h"

@implementation NSLayoutConstraint (EvenDistribution)

+ (NSArray *) fluidConstraintWithItems:(NSDictionary *) dictViews
                              asString:(NSArray *) stringViews
                             alignAxis:(NSString *) axis
                        verticalMargin:(NSUInteger) vMargin
                      horizontalMargin:(NSUInteger) hMargin
                           innerMargin:(NSUInteger) iMargin

{
    NSMutableArray *constraints = [NSMutableArray arrayWithCapacity: dictViews.count];
    NSMutableString *globalFormat = [NSMutableString stringWithFormat:@"%@:|-%d-",
                                     axis,
                                     [axis isEqualToString:@"V"] ? vMargin : hMargin
                                     ];



        for (NSUInteger i = 0; i < dictViews.count; i++) {

            if (i == 0)
                [globalFormat appendString:[NSString stringWithFormat: @"[%@]-%d-", stringViews[i], iMargin]];
            else if(i == dictViews.count - 1)
                [globalFormat appendString:[NSString stringWithFormat: @"[%@(==%@)]-", stringViews[i], stringViews[i-1]]];
            else
               [globalFormat appendString:[NSString stringWithFormat: @"[%@(==%@)]-%d-", stringViews[i], stringViews[i-1], iMargin]];

            NSString *localFormat = [NSString stringWithFormat: @"%@:|-%d-[%@]-%d-|",
                                     [axis isEqualToString:@"V"] ? @"H" : @"V",
                                     [axis isEqualToString:@"V"] ? hMargin : vMargin,
                                     stringViews[i],
                                     [axis isEqualToString:@"V"] ? hMargin : vMargin];

            [constraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:localFormat
                                                                                     options:0
                                                                                     metrics:nil
                                                                                       views:dictViews]];


    }
    [globalFormat appendString:[NSString stringWithFormat:@"%d-|",
                                [axis isEqualToString:@"V"] ? vMargin : hMargin
                                ]];

    [constraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:globalFormat
                                                                             options:0
                                                                             metrics:nil
                                                                               views:dictViews]];

    return constraints;

}

@end

J
James

是的,您可以仅在界面生成器中执行此操作而无需编写代码 - 需要注意的是您正在调整标签大小而不是分配空白。在这种情况下,将标签 2 的 X 和 Y 与超级视图对齐,使其固定在中心。然后将标签 1 的垂直空间设置为超级视图并将标签 2 设置为标准,对标签 3 重复此操作。设置标签 2 后,设置标签 1 和 3 的最简单方法是调整它们的大小直到它们对齐。

https://i.stack.imgur.com/e9Ivu.png

https://i.stack.imgur.com/wHMJJ.png

我意识到由于标签之间的标准空间和超级视图之间的标准空间之间的差异,它们在基线之间并不是绝对 100% 等间距的。如果这让您感到困扰,请将大小设置为 0 而不是标准


V
Vladimír Slavík

我只为第一项设置宽度值(>= 宽度)和每个项目之间的最小距离(>= 距离)。然后我使用 Ctrl 将第二个、第三个...项目拖到第一个项目上,以链接项目之间的依赖关系。

https://i.stack.imgur.com/TYw1V.png


T
Taku

聚会迟到了,但我有一个可行的解决方案,可以用间距水平创建菜单。可以使用 NSLayoutConstraint 中的 == 轻松完成

const float MENU_HEIGHT = 40;

- (UIView*) createMenuWithLabels: (NSArray *) labels
    // labels is NSArray of NSString
    UIView * backgroundView = [[UIView alloc]init];
    backgroundView.translatesAutoresizingMaskIntoConstraints = false;

    NSMutableDictionary * views = [[NSMutableDictionary alloc] init];
    NSMutableString * format = [[NSMutableString alloc] initWithString: @"H:|"];
    NSString * firstLabelKey;

    for(NSString * str in labels)
    {
        UILabel * label = [[UILabel alloc] init];
        label.translatesAutoresizingMaskIntoConstraints = false;
        label.text = str;
        label.textAlignment = NSTextAlignmentCenter;
        label.textColor = [UIColor whiteColor];
        [backgroundView addSubview: label];
        [label fixHeightToTopBounds: MENU_HEIGHT-2];
        [backgroundView addConstraints: [label fixHeightToTopBounds: MENU_HEIGHT]];
        NSString * key = [self camelCaseFromString: str];
        [views setObject: label forKey: key];
        if(firstLabelKey == nil)
        {
            [format appendString: [NSString stringWithFormat: @"[%@]", key]];
            firstLabelKey = key;
        }
        else
        {
            [format appendString: [NSString stringWithFormat: @"[%@(==%@)]", key, firstLabelKey]];
        }
    }

    [format appendString: @"|"];

    NSArray * constraints = [NSLayoutConstraint constraintsWithVisualFormat: (NSString *) format
                                                                               options: 0
                                                                               metrics: nil
                                                                                 views: (NSDictionary *) views];
    [backgroundView addConstraints: constraints];
    return backgroundView;
}

A
Adriana Pineda

我想水平对齐 5 张图像,所以我最终遵循了 Mete 的 response,但差别很小。

第一个图像将在容器中水平居中,等于 0 和 1:5 的乘数:

https://i.stack.imgur.com/A3Xvo.png

https://i.stack.imgur.com/5Uhna.png

https://i.stack.imgur.com/x2Roo.png

正如 Mete 解释的那样,顺序是 1、3、5、7、9 等。位置遵循相同的逻辑:第一个位置是 1,然后是空格,然后是下一个位置 3,依此类推。


S
Sam Corder

Android 有一种在我想模仿的基于约束的布局系统中将视图链接在一起的方法。搜索把我带到了这里,但没有一个答案很有效。我不想使用 StackViews,因为它们往往会给我带来更多的悲伤,而不是它们预先保存的内容。我最终创建了一个使用放置在视图之间的 UILayoutGuides 的解决方案。控制它们的宽度允许不同类型的分布,Android 用语中的链样式。该函数接受前导和尾随锚而不是父视图。这允许将链放置在两个任意视图之间,而不是分布在父视图内部。它确实使用了仅在 iOS 9+ 中可用的 UILayoutGuide,但这应该不再是问题了。

public enum LayoutConstraintChainStyle {
    case spread //Evenly distribute between the anchors
    case spreadInside //Pin the first & last views to the sides and then evenly distribute
    case packed //The views have a set space but are centered between the anchors.
}

public extension NSLayoutConstraint {

    static func chainHorizontally(views: [UIView],
                                  leadingAnchor: NSLayoutXAxisAnchor,
                                  trailingAnchor: NSLayoutXAxisAnchor,
                                  spacing: CGFloat = 0.0,
                                  style: LayoutConstraintChainStyle = .spread) -> [NSLayoutConstraint] {
    var constraints = [NSLayoutConstraint]()
    guard views.count > 1 else { return constraints }
    guard let first = views.first, let last = views.last, let superview = first.superview else { return constraints }

    //Setup the chain of views
    var distributionGuides = [UILayoutGuide]()
    var previous = first
    let firstGuide = UILayoutGuide()
    superview.addLayoutGuide(firstGuide)
    distributionGuides.append(firstGuide)
    firstGuide.identifier = "ChainDistribution\(distributionGuides.count)"
    constraints.append(firstGuide.leadingAnchor.constraint(equalTo: leadingAnchor))
    constraints.append(first.leadingAnchor.constraint(equalTo: firstGuide.trailingAnchor, constant: spacing))
    views.dropFirst().forEach { view in
        let g = UILayoutGuide()
        superview.addLayoutGuide(g)
        distributionGuides.append(g)
        g.identifier = "ChainDistribution\(distributionGuides.count)"
        constraints.append(contentsOf: [
            g.leadingAnchor.constraint(equalTo: previous.trailingAnchor),
            view.leadingAnchor.constraint(equalTo: g.trailingAnchor)
        ])
        previous = view
    }
    let lastGuide = UILayoutGuide()
    superview.addLayoutGuide(lastGuide)
    constraints.append(contentsOf: [lastGuide.leadingAnchor.constraint(equalTo: last.trailingAnchor),
                                    lastGuide.trailingAnchor.constraint(equalTo: trailingAnchor)])
    distributionGuides.append(lastGuide)

    //Space the according to the style.
    switch style {
    case .packed:
        if let first = distributionGuides.first, let last = distributionGuides.last {
            constraints.append(first.widthAnchor.constraint(greaterThanOrEqualToConstant: spacing))
            constraints.append(last.widthAnchor.constraint(greaterThanOrEqualToConstant: spacing))
            constraints.append(last.widthAnchor.constraint(equalTo: first.widthAnchor))
            constraints.append(contentsOf:
                distributionGuides.dropFirst().dropLast()
                    .map { $0.widthAnchor.constraint(equalToConstant: spacing) }
                )
        }
    case .spread:
        if let first = distributionGuides.first {
            constraints.append(contentsOf:
                distributionGuides.dropFirst().map { $0.widthAnchor.constraint(equalTo: first.widthAnchor) })
        }
    case .spreadInside:
        if let first = distributionGuides.first, let last = distributionGuides.last {
            constraints.append(first.widthAnchor.constraint(equalToConstant: spacing))
            constraints.append(last.widthAnchor.constraint(equalToConstant: spacing))
            let innerGuides = distributionGuides.dropFirst().dropLast()
            if let key = innerGuides.first {
                constraints.append(contentsOf:
                    innerGuides.dropFirst().map { $0.widthAnchor.constraint(equalTo: key.widthAnchor) }
                )
            }
        }
    }

    return constraints
}

h
halfer

您可以只创建一个 tableView 并制作 isScrollEnabled = false


不理解反对票,我的解决方案是跳出框框思考。当 cocoa 在 UITableView 中为您提供列表时,为什么还要为使用自动布局创建列表而头疼呢?

关注公众号,不定期副业成功案例分享
关注公众号

不定期副业成功案例分享

领先一步获取最新的外包任务吗?

立即订阅