ios setNeedsLayout 与 setNeedsUpdateConstraints 和 layoutIfNeeded 与 updateConstraintsIfNeeded

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/20609206/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 22:47:31  来源:igfitidea点击:

setNeedsLayout vs. setNeedsUpdateConstraints and layoutIfNeeded vs updateConstraintsIfNeeded

iosobjective-cautolayoutnslayoutconstraint

提问by Andrea

I know that the auto layout chain consists in basically 3 different process.

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

  1. updating constraints
  2. layout views (here is where we get calculation of frames)
  3. display
  1. 更新约束
  2. 布局视图(这里是我们计算帧的地方)
  3. 展示

What's is not totally clear to me is the inner difference between -setNeedsLayoutand -setNeedsUpdateConstraints. From Apple Docs:

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

setNeedsLayout

设置需要布局

Call this method on your application's main thread when you want to adjust the layout of a view's subviews. This method makes a note of the request and returns immediately. Because this method does not force an immediate update, but instead waits for the next update cycle, you can use it to invalidate the layout of multiple views before any of those views are updated. This behavior allows you to consolidate all of your layout updates to one update cycle, which is usually better for performance.

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

setNeedsUpdateConstraints

setNeedsUpdateConstraints

When a property of your custom view changes in a way that would impact constraints, you can call this method to indicate that the constraints need to be updated at some point in the future. The system will then call updateConstraints as part of its normal layout pass. Updating constraints all at once just before they are needed ensures that you don't needlessly recalculate constraints when multiple changes are made to your view in between layout passes.

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

When I want to animate a view after modifying a constraint and animate the changes I usually call for instance:

当我想在修改约束后为视图设置动画并为我通常调用的更改设置动画时:

[UIView animateWithDuration:1.0f delay:0.0f usingSpringWithDamping:0.5f initialSpringVelocity:1 options:UIViewAnimationOptionCurveEaseInOut animations:^{
        [self.modifConstrView setNeedsUpdateConstraints];
        [self.modifConstrView layoutIfNeeded];
    } completion:NULL];

I've found out that if I use -setNeedsLayoutinstead of -setNeedsUpdateConstraintseverything work as expected, but if I change -layoutIfNeededwith -updateConstraintsIfNeeded, the animation won't happen.
I've tried to make my own conclusion:

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

  • -updateConstraintsIfNeededonly update constraints but doesn't force the layout to come into the process, thus original frames are still preserved
  • -setNeedsLayoutcalls also -updateContraintsmethod
  • -updateConstraintsIfNeeded只更新约束但不强制布局进入过程,因此原始帧仍然保留
  • -setNeedsLayout也调用-updateContraints方法

So when is ok to use one instead of the other? and about the layout methods, do I need to call them on the view that has a change in a constraint or on the parent view?

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

回答by coverback

Your conclusions are right.The basic scheme is:

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

  • setNeedsUpdateConstraintsmakes sure a future call to updateConstraintsIfNeededcalls updateConstraints.
  • setNeedsLayoutmakes sure a future call to layoutIfNeededcalls layoutSubviews.
  • setNeedsUpdateConstraints确保将来调用updateConstraintsIfNeededcall updateConstraints
  • setNeedsLayout确保将来调用layoutIfNeededcall layoutSubviews

When layoutSubviewsis called, it also calls updateConstraintsIfNeeded, so calling it manually is rarely needed in my experience. In fact, I have never called it except when debugging layouts.

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

Updating constraints using setNeedsUpdateConstraintsis pretty rare too, objc.io–a must read about autolayouts–says:

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

If something changes later on that invalidates one of your constraints, you should remove the constraint immediately and call setNeedsUpdateConstraints. In fact, that's the only case where you should have to trigger a constraint update pass.

如果稍后发生的更改使您的约束之一无效,您应该立即删除该约束并调用 setNeedsUpdateConstraints。事实上,这是您必须触发约束更新传递的唯一情况。

In addition, in my experience, I have never had to invalidate constraints, and not set the setNeedsLayoutin the next line of the code, because new constraints pretty much are asking for a new layout.

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

The rules of thumb are:

经验法则是:

  • If you manipulated constraints directly, call setNeedsLayout.
  • If you changed some conditions (like offsets or smth) which wouldchange constraints in your overridden updateConstraintsmethod (a recommended way to change constraints, btw), call setNeedsUpdateConstraints, and most of the time, setNeedsLayoutafter that.
  • If you need any of the actions above to have immediate effect—e.g. when your need to learn new frame height after a layout pass—append it with a layoutIfNeeded.
  • 如果您直接操作约束,请调用setNeedsLayout.
  • 如果您更改了一些条件(例如偏移量或 smth),这更改您的重写updateConstraints方法中的约束(一种推荐的更改约束的方法,顺便说一句),则调用setNeedsUpdateConstraints,并且大多数情况下,setNeedsLayout在此之后。
  • 如果您需要上述任何操作立即生效(例如,当您需要在布局通过后学习新的框架高度时),请将layoutIfNeeded.

Also, in your animation code, I believe setNeedsUpdateConstraintsis unneeded, since constraints are updated before the animation manually, and the animation only re-lays-out the view based on differences between the old and new ones.

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

回答by Kunal Balani

The answer by coverbackis pretty correct. However, I would like to add some additional details.

掩护答案是非常正确的。但是,我想添加一些额外的细节。

Below is the diagram of a typical UIView cycle which explains other behaviors:

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

UIView's Lifecycle

UIView 的生命周期

  1. I've found out that if I use -setNeedsLayoutinstead of -setNeedsUpdateConstraintseverything work as expected, but if I change -layoutIfNeededwith -updateConstraintsIfNeeded, the animation won't happen.
  1. 我发现如果我使用-setNeedsLayout而不是-setNeedsUpdateConstraints一切都按预期工作,但是如果我更改-layoutIfNeeded-updateConstraintsIfNeeded,动画将不会发生。

updateConstraintstypically doesn't do anything. It just resolves constraints it doesn't apply them till layoutSubviewsis called. So animation does requires a call to layoutSubviews.

updateConstraints通常什么都不做。它只是解决layoutSubviews在调用之前不应用它们的约束。所以动画确实需要调用layoutSubviews.

  1. setNeedsLayout calls also -updateContraints method
  1. setNeedsLayout 也调用 -updateContraints 方法

No this is not necessary. If your constraints haven't been modified UIView will skip call to updateConstraints. You need to explicitly call setNeedsUpdateConstraintto modify constraints in the process.

不,这不是必需的。如果您的约束尚未修改,则 UIView 将跳过对updateConstraints. 您需要显式调用setNeedsUpdateConstraint以修改流程中的约束。

In order to call updateConstraintsyou need to do the following:

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

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