我知道自动布局链基本上包含 3 个不同的过程。
更新约束布局视图(这里是我们计算帧的地方)显示
我不完全清楚的是 -setNeedsLayout
和 -setNeedsUpdateConstraints
之间的内在区别。来自 Apple 文档:
当您想要调整视图的子视图的布局时,请在应用程序的主线程上调用此方法。此方法记录请求并立即返回。由于此方法不强制立即更新,而是等待下一个更新周期,因此您可以使用它在更新这些视图中的任何一个之前使多个视图的布局无效。此行为允许您将所有布局更新合并到一个更新周期,这通常对性能更好。
当您的自定义视图的属性以影响约束的方式发生变化时,您可以调用此方法来指示约束需要在将来的某个时间点进行更新。然后系统将调用 updateConstraints 作为其正常布局传递的一部分。在需要之前一次性更新所有约束,确保在布局传递之间对视图进行多项更改时,您不会不必要地重新计算约束。
当我想在修改约束后为视图设置动画并为我通常调用的更改设置动画时,例如:
[UIView animateWithDuration:1.0f delay:0.0f usingSpringWithDamping:0.5f initialSpringVelocity:1 options:UIViewAnimationOptionCurveEaseInOut animations:^{
[self.modifConstrView setNeedsUpdateConstraints];
[self.modifConstrView layoutIfNeeded];
} completion:NULL];
我发现如果我使用 -setNeedsLayout
而不是 -setNeedsUpdateConstraints
,一切都会按预期工作,但如果我将 -layoutIfNeeded
更改为 -updateConstraintsIfNeeded
,动画将不会发生。
我尝试制作我自己的结论:
-updateConstraintsIfNeeded 仅更新约束但不强制布局进入流程,因此仍保留原始帧
-setNeedsLayout 还调用 -updateContraints 方法
那么什么时候可以使用一个而不是另一个呢?关于布局方法,我是否需要在约束发生变化的视图或父视图上调用它们?
你的结论是对的。基本方案是:
setNeedsUpdateConstraints 确保将来调用 updateConstraintsIfNeeded 调用 updateConstraints。
setNeedsLayout 确保将来对 layoutIfNeeded 的调用会调用 layoutSubviews。
调用 layoutSubviews
时,它也会调用 updateConstraintsIfNeeded
,因此根据我的经验,很少需要手动调用它。事实上,除了调试布局时,我从未调用过它。
使用 setNeedsUpdateConstraints
更新约束也非常少见,objc.io–a must read about autolayouts–says:
如果稍后发生某些更改使您的约束之一无效,则应立即删除该约束并调用 setNeedsUpdateConstraints。事实上,这是您必须触发约束更新传递的唯一情况。
此外,根据我的经验,我从来不需要使约束无效,也不必在代码的下一行设置 setNeedsLayout
,因为新约束几乎要求新布局。
经验法则是:
如果您直接操作约束,请调用 setNeedsLayout。
如果您更改了一些条件(如偏移量或 smth),这些条件会更改覆盖的 updateConstraints 方法中的约束(顺便说一句,这是更改约束的推荐方法),请调用 setNeedsUpdateConstraints,然后在大多数情况下调用 setNeedsLayout。
如果您需要上述任何操作来立即生效——例如,当您需要在布局通过后学习新的帧高度时——将其附加一个 layoutIfNeeded。
另外,在您的动画代码中,我认为不需要 setNeedsUpdateConstraints
,因为在动画之前手动更新约束,并且动画仅根据新旧视图之间的差异重新布置视图。
answer by coverback 非常正确。但是,我想补充一些额外的细节。
下面是一个典型的 UIView 循环图,它解释了其他行为:
https://i.stack.imgur.com/i9YuN.png
我发现如果我使用 -setNeedsLayout 而不是 -setNeedsUpdateConstraints 一切都会按预期工作,但如果我将 -layoutIfNeeded 更改为 -updateConstraintsIfNeeded,动画将不会发生。
updateConstraints
通常不执行任何操作。它只是解决在调用 layoutSubviews
之前不会应用它们的约束。所以动画确实需要调用 layoutSubviews
。
setNeedsLayout 还调用 -updateContraints 方法
不,这不是必需的。如果您的约束尚未修改,UIView 将跳过对 updateConstraints
的调用。您需要显式调用 setNeedsUpdateConstraint
来修改过程中的约束。
为了调用 updateConstraints
,您需要执行以下操作:
[view setNeedsUpdateConstraints];
[view setNeedsLayout];
[view layoutIfNeeded];
setNeedsLayout
。setNeedsLayout
确保layoutSubviews
将在下一个更新周期中被调用,但这可能与layoutIfNeeded
无关?layoutSubviews
,不需要调用setNeedsLayout
layoutSubviews
,因此无需手动操作。但是,如果您需要更改立即生效而不是下一个布局周期,则必须调用layoutIfNeeded