setNeedsLayout vs setNeedsUpdateConstraints和layoutIfNeeded vs updateConstraintsIfNeeded

我知道自动布局链基本上由3个不同的过程组成。

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

什么是不完全清楚的是-setNeedsLayout-setNeedsUpdateConstraints之间的内在区别。 来自Apple Docs:

setNeedsLayout

当您想要调整视图子视图的布局时,在应用程序的主线程上调用此方法。 此方法logging请求并立即返回。 由于此方法不会强制立即更新,而是等待下一个更新周期,因此您可以在更新任何视图之前使用它来使多个视图的布局无效。 此行为允许您将所有布局更新合并到一个更新周期,这通常对性能更好。

setNeedsUpdateConstraints

当自定义视图的属性以影响约束的方式进行更改时,可以调用此方法来指示约束需要在将来的某个时间点更新。 然后系统将调用updateConstraints作为其正常布局阶段的一部分。 在需要之前立即更新约束可确保在布局阶段之间对视图进行多个更改时,不会不必要地重新计算约束。

当我想在修改一个约束之后为视图添加animation,并为我通常调用的变化设置animation效果时:

 [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-layoutIfNeeded ,animation将不会发生。
我试图做出自己的结论:

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

那么什么时候可以使用一个而不是另一个呢? 关于布局方法,我是否需要在约束或父视图中有更改的视图上调用它们?

你的结论是对的。 基本scheme是:

  • setNeedsUpdateConstraints确保未来调用updateConstraintsIfNeeded调用updateConstraints
  • setNeedsLayout确保以后调用layoutIfNeeded调用layoutSubviews

layoutSubviews被调用时,它也调用updateConstraintsIfNeeded ,所以根据我的经验,很less需要手动调用它。 事实上,除了debugging布局以外,我从来没有调用过它。

更新约束使用setNeedsUpdateConstraints也是非常罕见的, objc.io – 必须阅读有关自动布局 – 说 :

如果稍后发生某些更改会使您的某个约束失效,则应立即删除该约束并调用setNeedsUpdateConstraints。 事实上,这是唯一的情况下,你应该不得不触发约束更新通行证。

另外,根据我的经验,我从来没有必要使约束失效,也没有在代码的下一行设置setNeedsLayout ,因为新约束几乎要求新的布局。

经验法则是:

  • 如果您直接操作约束,请调用setNeedsLayout
  • 如果你改变了一些改变约束的条件(如offset或者smth),这改变你重载的updateConstraints方法(推荐的改变约束的方法,btw)中的约束,那么在setNeedsUpdateConstraintssetNeedsLayout之后调用setNeedsUpdateConstraints
  • 如果您需要上述任何操作,立即生效 – 例如,当您需要在布局通过之后学习新的框架高度时,将其附加到layoutIfNeeded

另外,在你的animation代码中,我相信setNeedsUpdateConstraints是不需要的,因为约束是在手动animation之前更新的,而animation只是根据新旧差异来重新布局视图。

封面的答案是非常正确的。 不过,我想补充一些额外的细节。

下面是一个典型的UIView循环图解释其他行为 UIView的生命周期

  1. 我发现,如果我使用-setNeedsLayout而不是-setNeedsUpdateConstraints,一切都按预期工作,但如果我更改-layoutIfNeeded和-updateConstraintsIfNeeded,animation将不会发生。

updateConstraints通常不会执行任何操作。 它只是解决了它不适用的约束,直到layoutSubviews被调用。 所以animation确实需要调用layoutSubviews

  1. setNeedsLayout也调用-updateContraints方法

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

为了调用updateConstraints你需要执行以下操作:

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