setNeedsLayout与setNeedsUpdateConstraints和layoutIfNeeded vs updateConstraintsIfNeeded

And*_*rea 220 objective-c ios autolayout nslayoutconstraint

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

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

我不完全清楚的是-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];
Run Code Online (Sandbox Code Playgroud)

我发现,如果我使用-setNeedsLayout的,而不是-setNeedsUpdateConstraints一切都按预期工作,但如果我改变-layoutIfNeeded-updateConstraintsIfNeeded,动画将不会发生.
我试图得出自己的结论:

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

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

cov*_*ack 256

你的结论是对的.基本方案是:

  • setNeedsUpdateConstraints确保将来拨打updateConstraintsIfNeeded电话updateConstraints.
  • setNeedsLayout确保将来拨打layoutIfNeeded电话layoutSubviews.

layoutSubviews被调用时,它也会调用updateConstraintsIfNeeded,因此在我的经验中很少需要手动调用它.事实上,除了在调试布局时,我从未调用它.

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

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

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

经验法则是:

  • 如果直接操纵约束,请调用setNeedsLayout.
  • 如果你改变了一些条件(比如偏移或smth),这些条件改变被覆盖updateConstraints方法中的约束(推荐的改变约束的方法,顺便说一下),调用setNeedsUpdateConstraints,大部分时间都会调用setNeedsLayout.
  • 如果您需要上述任何操作立即生效 - 例如,当您需要在布局传递后学习新的帧高度时 - 将其附加到layoutIfNeeded.

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

  • @pash3r差异是更新常量不符合"无效".失效是指它根本不再相关,例如必须附加到另一个视图或完全删除.常量只会将视图放得更近或更远,或者改变它的大小,因此需要`setNeedsLayout`. (3认同)
  • @coverback如果直接操作约束,将自动调用`layoutSubviews`,无需调用`setNeedsLayout` (2认同)

Kun*_*ani 87

回避答案非常正确.但是,我想补充一些其他细节.

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

UIView的生命周期

  1. 我发现,如果我使用-setNeedsLayout的,而不是-setNeedsUpdateConstraints一切都按预期工作,但如果我改变-layoutIfNeeded-updateConstraintsIfNeeded,动画将不会发生.

updateConstraints通常什么都不做.它只是解决了在layoutSubviews调用之前它不会应用它们的约束.所以动画需要打电话layoutSubviews.

  1. setNeedsLayout也调用-updateContraints方法

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

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

[view setNeedsUpdateConstraints];
[view setNeedsLayout]; 
[view layoutIfNeeded];
Run Code Online (Sandbox Code Playgroud)