setNeedsLayout与setNeedsUpdateConstraints和layoutIfNeeded vs updateConstraintsIfNeeded

时间:2013-12-16 10:58:17

标签: ios objective-c autolayout nslayoutconstraint

我知道汽车布局链基本上包含3个不同的过程。

  1. 更新约束
  2. 布局视图(这里是我们计算框架的地方)
  3. 显示
  4. 我不完全清楚的是-setNeedsLayout-setNeedsUpdateConstraints之间的内在差异。来自Apple Docs:

    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,一切都按预期工作,但如果我用-layoutIfNeeded更改-updateConstraintsIfNeeded,则动画不会发生。
    我试图得出自己的结论:

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

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

2 个答案:

答案 0 :(得分:253)

您的结论是对的。基本方案是:

  • setNeedsUpdateConstraints确保以后拨打updateConstraintsIfNeeded来电updateConstraints
  • setNeedsLayout确保以后拨打layoutIfNeeded来电layoutSubviews

调用layoutSubviews时,它也会调用updateConstraintsIfNeeded,因此根据我的经验,很少需要手动调用它。实际上,除了在调试布局时,我从未调用它。

使用setNeedsUpdateConstraints更新约束的情况非常罕见,objc.io–a must read about autolayouts–says

  

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

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

经验法则是:

  • 如果您直接操纵约束,请致电setNeedsLayout
  • 如果您更改了某些条件(例如偏移或smth)更改已覆盖的updateConstraints方法中的约束(建议更改约束的方法,顺便说一下),请调用{{1}在大多数情况下,setNeedsUpdateConstraints之后。{/ li>
  • 如果您需要上述任何行动立即生效 - 例如。当你需要在布局传递后学习新的框架高度时 - 用setNeedsLayout附加它。

此外,在您的动画代码中,我认为layoutIfNeeded是不需要的,因为约束会在动画之前手动更新,并且动画只会根据旧视图和新视图之间的差异重新布置视图。

答案 1 :(得分:81)

answer by coverback非常正确。但是,我想补充一些其他细节。

以下是解释其他行为的典型UIView循环图:

UIView's Lifecycle

  1. 我发现如果我使用-setNeedsLayout代替-setNeedsUpdateConstraints,一切都按预期工作,但如果我使用-layoutIfNeeded更改-updateConstraintsIfNeeded,动画不会发生。
  2. updateConstraints通常无法做任何事情。它只是解决了在调用layoutSubviews之前它不会应用它们的约束。因此动画需要调用layoutSubviews

    1. setNeedsLayout也会调用-updateContraints方法
    2. 不,这不是必要的。如果您的约束未被修改,UIView将跳过对updateConstraints的调用。您需要显式调用setNeedsUpdateConstraint来修改流程中的约束。

      要拨打updateConstraints,您需要执行以下操作:

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