为啥自动布局不能产生一致的结果?

Posted

技术标签:

【中文标题】为啥自动布局不能产生一致的结果?【英文标题】:Why does Autolayout not produce consistent results?为什么自动布局不能产生一致的结果? 【发布时间】:2016-04-30 00:32:28 【问题描述】:

要么我疯了,要么 AutoLayout 直接坏掉了。有人可以向我解释一下吗。我在TableView 中有一个TableViewCell,它跨越了ViewController 的宽度。我在TableViewCell 中放置了 4 个标签。我使用 AutoLayout 创建了约束,使每个标签的宽度为TableViewCell 的 25%。然而,这 4 个标签的宽度明显不同,它们甚至不等于整个单元格宽度的 100%。这是屏幕截图。 (每个标签的水平位置都是模棱​​两可的,是的,但这不应该有所作为)。为什么它们的宽度不一样?为什么 25% + 25% + 25% + 25% 加起来不是 100%?运行 XCode 7.2 并针对 ios 9。

【问题讨论】:

是否需要宽度限制(优先级为 1000? 删除所有约束。尝试这些约束一次选择所有 4 个视图,而不是给出顶部、前导、尾随和等宽约束。 “每个标签的水平位置是模棱两可的,是的,但这不应该有所作为” - 不,它确实有所作为。这是 Autolayout 告诉你它必须做出一些猜测来布局你的项目。这些猜测不是你想要的。 @Paulw11 当然,它所做的猜测只是视图的水平位置,对吧?我看不出有一个模棱两可的水平位置应该如何影响视图的宽度...... AutoLayout 应该能够在不改变宽度的情况下猜测水平布局,这是明确指定的吧?否则,这意味着“如果您未指定任何 1 个约束,AutoLayout 会将所有其他约束抛出窗口”——这真的是它的工作原理吗? 不行,如果它不能解决水平位置,那么它可能也无法解决水平宽度。一般来说,如果你在 IB 中收到这些警告,那么事情就不会顺利。 【参考方案1】:

这个红色错误符号是 Interface Builder 告诉你它不能解决你的约束。在这种情况下,正如您所说,这可能是因为您没有为标签提供 x 位置约束。

自动布局可以解决所有约束并获得正确的布局,或者不能,结果将是未定义的。请记住,自动布局是一个基于代数的过程,它通过使用您在约束中提供的已知值来解决未知值。如果您不提供足够且明确的已知值,则根本无法求解剩余值的方程,并且无法期望得到正确的结果。解决方案是创建足够的约束以使布局可解决。

作为说明,从 iOS 9 开始,我建议使用 UIStackView 来保存这些标签。 UIStackView 的存在正是为了消除为这些类型的场景设置手动约束的痛苦。如果您在单元格中使用水平堆栈视图,您可以将其边缘约束到单元格的边缘,将 4 个标签拖入其中并将其设置为“平等填充”。这就是您所需要的!

【讨论】:

丹,谢谢你的回答。同意,我可以使用堆栈视图来完成这项工作。我只是困惑为什么不指定水平位置会影响视图的宽度。您关于这一切都基于一堆公式的解释是有道理的,如果您让 1 个约束模棱两可,AutoLayout 将破坏并出错所有剩余的不模棱两可的约束,这似乎很疯狂。如果这是真的,那么我想这是正确的答案哈 @A.Vin 当您考虑到宽度约束不一定习惯于在最终计算中设置“宽度”时,它会更有意义。最终,自动布局是计算一个 frame,而宽度约束提供了一个规则,即 frame 的右边缘或左边缘相对于相对边缘的位置。但是,如果对边未定义(没有 x 位置约束),您最终不会得到匹配的最终宽度,您最终会得到一个更像 left: ??, top: 0, right: ?? +一些宽度,底部:50。确切的坐标是什么? + 一些宽度?【参考方案2】:

Daniel Hall 的回答提供了有用的信息,但没有具体告诉你为什么你会看到你所看到的,所以我会的。

Xcode 并不总是在故事板编辑器中强制执行您的约束,除非您要求它这样做。在这种情况下,您可以选择表格视图单元格的内容视图,然后从菜单栏中选择编辑器 > 解决自动布局问题 > BBRowTableViewCell 中的所有视图 > 更新框架。 (有时 Xcode 需要尝试两三次才能把所有东西都弄好。)

但是,您可能不会喜欢这个结果。因为您没有限制标签的水平位置,Xcode 可能会将它们全部堆积在单元格的左边缘,或者可能在单元格边界之外您甚至看不到它们的某个地方。

如果您的部署目标是 iOS 9 或更高版本,最简单的解决方案(如 Daniel Hall 所说)是将标签放入设置为“Fill Equally”的UIStackView,并将堆栈视图的边缘限制为单元格内容视图的边缘边缘。

如果您的部署目标早于 iOS 9,那么您应该创建由 user3802077 描述的约束。

【讨论】:

Rob,感谢您的回答 - 我已经告诉 XCode 自动解决布局问题 - 根据我的警告,唯一未解决的问题是不明确的水平位置。听起来(基于丹尼尔的回答)答案基本上是“如果你让任何一个约束模棱两可,自动布局可能会崩溃,甚至让你指定的约束出错。”这真的正确吗?我没有足够的ios经验知道。 1 模棱两可的东西可以抛出所有正确指定的约束似乎有点疯狂。感谢您的输入,将使用 stackview【参考方案3】:

这不是唯一的方法,但这是我通常的做法。

正如您对每个标签的顶部和底部所做的那样,然后:

label1 的前导到 superview 的前导 label4 的尾随到 superview 的尾随

然后是每个相邻标签的约束:

label1.trailing 到 label2.leading, ...

然后将每个标签的等宽约束放到label1:

label2 到 label1 label3 到 label1 label4 到 label1

应该是这样的。无需指定 25%。

【讨论】:

谢谢,这工作正常。但我的问题并不是真正的“我如何使这项工作”,而是“为什么我目前的方式没有工作”,如果这有意义的话。感谢您的意见!【参考方案4】:

对于自动布局约束,它需要对特定对象进行约束 x,y 位置和高度、宽度 如果您没有给出其中任何一项,则会向您显示错误。 因此,请确保为您的对象提供所有需要的约束。

iOS 9 及更高版本的其他选项是 uistackview。 这是您了解stackview的链接 https://m.youtube.com/watch?v=XqVWyA5PLwk

【讨论】:

以上是关于为啥自动布局不能产生一致的结果?的主要内容,如果未能解决你的问题,请参考以下文章

element ui select为啥不能自动回显

为啥自动布局与此布局有问题

为啥我取消选中内容布局指南后通过了自动布局检查

iOS自动布局:为啥不允许零乘数?

为啥更换模拟器后我的 VC 会移位?自动布局

UITableViewCell为啥会有自动布局约束冲突