自动布局没有明确的宽度约束和大于或等于尾随空间的行为不当

JK *_*iho 5 interface-builder uiscrollview ios autolayout nslayoutconstraint

我有一个滚动视图直接包含在视图控制器的内容视图中,在两个维度中都是完整大小.从滚动视图到其超视图(水平)和布局指南(垂直)的顶部,底部,前导和尾随空间约束都设置为0. VC最终意味着嵌套为一个或两个子视图控制器地方.我正在使用故事板.

我在滚动视图中放置了许多元素并将它们约束到它,但我看到了各种奇怪的行为.下面是一个屏幕截图,其中选择了滚动视图的所有子视图以显示其约束.滚动视图对顶层视图的四个约束在其中不可见.视图控制器已设置为自由形式大小,其顶级视图(以及相应的滚动视图的内容视图)高616点,保证在运行时需要滚动.

约束可视化

在分析屏幕截图之前,这里列出了我正在努力实现的事情.

  1. 元素之间的垂直间距由设计者设置并固定.(顺便说一句,此线框中的垂直约束,文本样式等都不是最终的;整个图像仅用于说明目的.)
  2. 所有标签(最顶层的标签除外)应以其固有尺寸开始,向上扩展到滚动视图的宽度(减去两侧标准的HIG水平空间20磅).
  3. 按钮不太可能比这更大,但在本地化意外的情况下,我们希望它们的行为就像标签一样.("另一个按钮"有一个额外的垂直≥约束;它与这个问题无关.)
  4. Web视图具有固定的高度,其宽度应由滚动视图的宽度确定; 两侧标准20 pt水平空间.
  5. 文本视图具有最小高度(此处为67磅),但如果包含的文本太大而不适合,则它们应垂直展开.它们都不可编辑或可滚动.与网络视图一样,它们与前缘和后缘之间的水平间隔为标准的20磅.

如您所见,没有一个元素具有明确的宽度约束.整个事物依赖于元素和滚动视图之间的前导和尾随空间约束.在我看来,布局在某种程度上优雅地适用于假想的未来超过320 pt的iPhone,而不会改变约束.它也可以在旋转到横向方向后工作(它可能看起来有点傻,但它会起作用).

我将逐步完成这些要点,必要时参考屏幕截图.

1:这很有效,这里没什么特别的.

2:标签的主要限制是所有简单的等于20磅的标准空间.尾随约束大于或等于20磅标准,表面上允许它们scrollView.frame.size.width-40变宽,但不宽.

3:2相同.

4和5:这里有趣的地方.Web视图和文本视图都列为Misplaced Views,IB表示它们的帧在运行时会有所不同.表示正确帧的橙色虚线边框仅水平到达具有大于或等于尾随约束的最长元素; 这里,它是"具有长标题的按钮",其右边缘是虚线边界边缘的结束.


构建这组视图及其约束,我预计会遇到一些麻烦.我知道让UITextViews垂直高于这里定义的≥67高度会很困难,也许只能通过代码实现.通过IB单独使标签和按钮按上述方式工作似乎也有点不确定.

想到的是网页和文本视图报告的正确框架只有最宽的标签或按钮宽.看起来,通过这种设置,滚动视图实际上不会是320点宽,而是只需要适合最长元素及其间距所需的宽度,并且Web和文本视图应该符合要求.鉴于滚动视图被严格限制在顶层视图的所有边上,设置为320点宽,我不知道为什么会这样.SOMETHING显然必须定义滚动视图的初始宽度,但为什么不是我从滚动视图到顶层视图的约束呢?

鉴于上述这组视图的规范,我需要做些什么才能改变它?

这个案例表明我还没有正确理解Auto Layout,我希望这些答案可以让我了解它的许多重要方面.

bil*_*tum 3

对于 Xcode 关于错误放置视图的警告,请在情节提要中选择视图控制器,点击画布右下角的“解决自动布局问题”按钮(它看起来像《星球大战》中的领带战斗机),然后选择“更新视图控制器中的所有框架”。这迫使你所有的观点都反映出它们的局限性。

使用自动布局UIScrollView是一种不同的动物;如此之多以至于苹果认为有必要就该问题发布技术说明:https://developer.apple.com/library/ios/technotes/tn2154/_index.html

当您连接子视图和滚动视图内壁之间的所有这些约束时,结果可能不是您所期望的。当您将子视图固定到滚动视图的两侧时,您实际上并没有确定子视图相对于滚动视图的位置。相反,您正在确定滚动视图的contentSize. 这很奇怪。

您正在使用技术说明中苹果所谓的纯自动布局方法。使用这种方法,子视图的约束必须决定滚动视图的contentSize.

让我们只采用其中一个子视图并忽略所有其余的,例如文本视图之一。我们只考虑沿水平轴的文本视图。如果您希望文本视图受到滚动视图宽度的约束而不进行任何水平滚动,则需要在文本视图上安装固定宽度约束,该约束恰好是滚动视图边界的宽度减去间隔符。执行此操作后,内容大小宽度将是左间隔符、文本视图的宽度和右间隔符的总和。

不幸的是,您无法安装在文本视图的宽度和滚动视图边界的宽度之间建立关系的约束。这真的太糟糕了。

我实际上不建议在文本视图上安装固定宽度约束。相反,我会重新开始并使用技术说明中苹果的“混合方法”。

使用混合方法,子视图的约束不会决定滚动视图的contentSize. 相反,您必须显式设置滚动视图contentSize和容器视图(即内容视图)的框架UIView

让我们回到UITextView水平轴。使用混合方法,您可以保留文本视图的约束不变(即没有固定宽度约束)。contentSize您最早可以显式设置滚动视图的宽度和内容视图框架的宽度viewDidLoad。您可以显式地将这些值设置为,self.view.bounds.size.width因为您的滚动视图紧贴主视图的两侧。

要实现混合方法,您必须UIView在代码中实例化内容视图 (),而不是将其translatesAutoresizingMaskIntoConstraints属性设置为NO。通过扩展,您可能还需要在代码中为所有这些子视图创建约束(我不知道有什么办法解决这个问题)。视觉格式字符串是乏味且重复的,但实际上,在配置复杂布局时(您的布局足够复杂),它们比 IB 中创建的约束更容易使用。

我在这里使用混合方法来解决 SO 挑战:/sf/answers/1523912561/。不幸的是,该解决方案尚未经过审查。我总是有可能疯了,我不知道自己在说什么。