使用自动布局动态更改子视图后调整超级视图的大小

Posted

技术标签:

【中文标题】使用自动布局动态更改子视图后调整超级视图的大小【英文标题】:resize superview after subviews change dynamically using autolayout 【发布时间】:2013-10-10 19:01:18 【问题描述】:

看在上帝的份上,我无法理解这个调整大小的超级视图的窍门。

我有一个UIView *superview 和 4 个UILabels。 2 用作其他 2 的标题。

所有4个中的内容都是来自数据库的动态内容。

SizeToFit vs SizeThatFits:(CGSize) vs UIView systemLayoutSizeFittingSize:,通过UILayoutFittingCompressedSizeUILayoutFittingExpandedSize

我以编程方式使用自动布局,并将超级视图高度设置为等于或大于一个虚拟数字。

我在哪里以及如何使用这些SizeToFit vs sizeThatFits:(CGSize) vs UIView systemLayoutSizeFittingSize:,通过UILayoutFittingCompressedSizeUILayoutFittingExpandedSize。我在堆栈上阅读了很多技巧,但最终一无所获。

我是否需要在特定位置重新计算超级视图的约束。可能在其控制器类中将高度设置为“@property”并删除并读取它? Atm 我试图把所有东西都放在任何地方,然后再放一些。我仍然得到相同大小的最终结果,虚拟高度和文本漂浮在外面。即使在子视图上设置了 clipsToBound。

我正在抓挠我的头发……帮助

【问题讨论】:

嘿,如果我可以看一下,你能把你的代码贴在 pastebin 上的某个地方吗?我遇到了类似的问题。已经一周或更长时间了。 【参考方案1】:

如果您使用自动布局,您需要执行以下操作:

    确保您没有向任何子视图添加固定宽度和/或高度约束(取决于您想要动态调整的尺寸)。这个想法是让每个子视图的内在内容大小决定子视图的高度。 UILabels 带有 4 个自动隐式约束,它们将(低于所需优先级)尝试将标签的框架保持在适合所有文本所需的确切大小。

    确保每个标签的边缘都牢固地连接到彼此的边缘及其父视图(具有必需的优先级约束)。您要确保,如果您想象其中一个标签的大小增加,这将迫使其他标签为其腾出空间,最重要的是迫使超级视图也扩大。

    仅向超级视图添加约束以设置其位置,而不是大小(至少,不是您希望它动态调整大小的维度)。请记住,如果你正确设置了内部约束,它的大小将由所有子视图的大小决定,因为它的边缘以某种方式连接到它们的边缘。

就是这样。你不需要调用sizeToFitsystemLayoutSizeFittingSize: 来让它工作,只需加载你的视图并设置文本就可以了。系统布局引擎将为您进行计算以解决您的约束。 (如果有的话,您可能需要在 superview 上调用 setNeedsLayout...但这不应该是必需的。)

【讨论】:

谢谢smileyborg。自从我在一个项目中间并没有完全得到你的东西以来,我的反应迟了。现在我有机会以编程方式处理更多约束,尤其是constraintsWithVisualFormat,我完全理解你的观点,包含的子视图拉伸并且有点将超级视图推到它的大小:) 再次感谢 我同意这个解决方案,但它对我不起作用,请查看***.com/questions/34635838/… 这个答案很神奇。让视图看起来不错,我的努力要少得多。 需要说明的是,如果你使用的是xib,你应该设置translatesAutoresizingMaskIntoConstraints = NO translatesAutoresizingMaskIntoConstraints = NO 是我的情况的答案。但是现在容器视图丢失了帧,它的原点总是(0,0),我不能把它放在我想要的地方。 ***.com/questions/45548372/…【参考方案2】:

使用容器视图

在下面的示例中,我有一个 30x30 的图像,UILabel 小于包含占位符文本的包含视图。我需要包含视图至少与图像一样大,但它需要增长以包含多行文本。

在视觉格式中,内部容器如下所示:

H:|-(15.0)-[image(30.0)]-(15.0)-[label]-(15.0)-|
V:|[image(30.0)]|
V:|[label(>=30.0)]|

然后,设置包含视图以匹配标签的高度。现在包含的视图将随着标签的大小而变化。

正如@smileyborg 在他的回答中指出的那样,将内容严格地连接到超级视图会通知布局引擎简单的容器视图应该使其增长。

黄色对齐矩形

如果您想要黄色对齐矩形,请在您的方案的运行参数列表中添加 -UIViewShowAlignmentRects YES

【讨论】:

-UIViewShowAlignmentRects YES -- 很棒的提示! 在这种情况下,容器只需要根据标签调整它的高度。如果容器应该适应多个视图的高度之和怎么办?【参考方案3】:

随着 ios 9 中堆栈视图的引入,这变得非常容易。在视图中使用堆栈视图来包含所有调整大小的内容,然后只需调用

view.setNeedsUpdateConstraints()
view.updateConstraintsIfNeeded()
view.setNeedsLayout()
view.layoutIfNeeded()

更改内容后。然后你可以通过调用来获得你的新尺寸

view.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize)

如果您需要计算视图所需的确切大小。

【讨论】:

我正在使用 StackView 并动态添加视图,这些视图没有调整大小。@JacobRuth【参考方案4】:

这几乎遵循@smileyborg 的回答,并附有一个具体的例子。

不会描述所有约束,而是描述与 UI 对象高度计算相关的约束。

    [Label] 标签不能有固定的height 约束,在这种情况下,AutoLayout 不会调整标签大小以适应文本,因此设置边缘约束是关键。 (绿色箭头)

    [Subview] 第 1 步和第 3 步很容易理解,但是这一步可能会被误解。与标签的情况一样,子视图不能有height 约束集。所有子视图都必须设置top约束,忽略bottom约束,这会让你认为会在运行时触发不满足约束异常,但如果你为最后一个子视图设置bottom约束,它不会。不这样做会破坏布局。 (红色箭头)

    [Superview] 按您需要的方式设置所有约束,但要特别注意 height 约束。为其分配一个随机值,但使其成为可选值,AutoLayout 将精确设置高度以适合子视图。 (蓝色箭头)

完美运行,无需调用任何额外的系统布局更新方法。

【讨论】:

如何使高度可选。我是 iOS 新手,所以无法弄清楚。谢谢

以上是关于使用自动布局动态更改子视图后调整超级视图的大小的主要内容,如果未能解决你的问题,请参考以下文章

如何使用自动布局动态更改超级视图的高度

根据子视图调整超级视图的大小

使用自动布局调整超级视图和所有超级视图的兄弟姐妹的大小

修改超级视图的框架时自动调整子视图的大小

使用自动调整子视图大小为 UIView 帧大小更改动画

iOS 故事板 - 自动布局不会调整子视图的大小和位置