setNeedsLayout vs. setNeedsUpdateConstraints和layoutIfNeeded vs. updateConstraintsIfNeeded

我知道自动布局链基本上包括3个不同的过程。

  1. 更新的约束
  2. 布局视图(这里是我们得到帧计算的地方)
  3. 显示

我不太清楚的是-setNeedsLayout-setNeedsUpdateConstraints之间的内在区别。从苹果文档:

setNeedsLayout

当你需要时,在你的应用程序主线程上调用这个方法 调整视图子视图的布局。这种方法做笔记 请求并立即返回。因为这个方法没有 强制立即更新,但等待下一次更新 循环,您可以使用它来使多个视图的布局无效 在更新这些视图之前。这种行为允许您 将所有布局更新合并到一个更新周期,即 通常性能更好。

setNeedsUpdateConstraints

当您的自定义视图的属性以一种会影响 约束,您可以调用此方法来指示约束 需要在将来的某个时候进行更新。系统将会 调用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,一切都能正常工作,但如果我用-updateConstraintsIfNeeded改变-layoutIfNeeded,动画就不会发生 我试图得出自己的结论:

  • -updateConstraintsIfNeeded只更新约束,但不强制布局进入过程,因此原始帧仍然保留
  • -setNeedsLayout也调用-updateContraints方法

那么什么时候用一种代替另一种合适呢?关于布局方法,我需要在约束发生变化的视图或父视图上调用它们吗?

103279 次浏览

你的结论是正确的。基本方案是:

  • setNeedsUpdateConstraints确保将来对updateConstraintsIfNeeded的调用会调用updateConstraints
  • setNeedsLayout确保将来对layoutIfNeeded的调用会调用layoutSubviews

layoutSubviews被调用时,它也会调用updateConstraintsIfNeeded,所以在我的经验中很少需要手动调用它。事实上,除了在调试布局时,我从来没有调用过它。

使用setNeedsUpdateConstraints更新约束也是非常罕见的,objc。io(关于自动布局的必读内容)说:

如果后来发生了一些变化,使某个约束失效,您应该立即删除该约束并调用setNeedsUpdateConstraints。事实上,这是您必须触发约束更新传递的唯一情况。

此外,根据我的经验,我从来没有使约束无效,也没有在下一行代码中设置setNeedsLayout,因为新的约束很大程度上要求新的布局。

经验法则是:

  • 如果直接操纵约束,则调用setNeedsLayout
  • 如果你改变了一些条件(如偏移量或smth),而在你重写的updateConstraints方法中改变了约束(顺便说一句,这是一种建议的改变约束的方法),调用setNeedsUpdateConstraints,大多数情况下,调用setNeedsLayout
  • 如果你需要上述任何一项措施立即生效,例如:当你需要在布局传递后了解新的帧高度时,使用layoutIfNeeded附加它。

同样,在你的动画代码中,我认为setNeedsUpdateConstraints是不需要的,因为约束在动画之前会手动更新,动画只会根据新旧之间的差异重新布局视图。

通过封面回答是非常正确的。但是,我想补充一些细节。

下面是一个典型的UIView循环图,它解释了其他行为:

UIView's Lifecycle

  1. 我发现,如果我使用-setNeedsLayout而不是-setNeedsUpdateConstraints,一切都能正常工作,但如果我用-updateConstraintsIfNeeded改变-layoutIfNeeded,动画就不会发生。

updateConstraints通常不做任何事情。它只是解决约束,直到layoutSubviews被调用才应用它们。所以动画确实需要调用layoutSubviews

  1. setNeedsLayout也调用-updateContraints方法

不,这没有必要。如果你的约束没有被修改,UIView将跳过调用updateConstraints。你需要显式地调用setNeedsUpdateConstraint来修改过程中的约束。

为了调用updateConstraints,你需要做以下事情:

[view setNeedsUpdateConstraints];
[view setNeedsLayout];
[view layoutIfNeeded];