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
setNeedsLayout vs. setNeedsUpdateConstraints and layoutIfNeeded vs updateConstraintsIfNeeded
提问by Andrea
I know that the auto layout chain consists in basically 3 different process.
我知道自动布局链基本上包含 3 个不同的过程。
- updating constraints
- layout views (here is where we get calculation of frames)
- display
- 更新约束
- 布局视图(这里是我们计算帧的地方)
- 展示
What's is not totally clear to me is the inner difference between -setNeedsLayout
and -setNeedsUpdateConstraints
. From Apple Docs:
我不太清楚的是-setNeedsLayout
和之间的内在区别-setNeedsUpdateConstraints
。来自苹果文档:
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.
当您想要调整视图子视图的布局时,请在应用程序的主线程上调用此方法。此方法记录请求并立即返回。由于此方法不会强制立即更新,而是等待下一个更新周期,因此您可以使用它在更新任何视图之前使多个视图的布局无效。此行为允许您将所有布局更新合并到一个更新周期,这通常对性能更好。
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 -setNeedsLayout
instead of -setNeedsUpdateConstraints
everything work as expected, but if I change -layoutIfNeeded
with -updateConstraintsIfNeeded
, the animation won't happen.
I've tried to make my own conclusion:
我发现如果我使用-setNeedsLayout
而不是-setNeedsUpdateConstraints
一切都按预期工作,但是如果我更改-layoutIfNeeded
为-updateConstraintsIfNeeded
,动画将不会发生。
我试图做出自己的结论:
-updateConstraintsIfNeeded
only update constraints but doesn't force the layout to come into the process, thus original frames are still preserved-setNeedsLayout
calls also-updateContraints
method
-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:
你的结论是对的。基本方案是:
setNeedsUpdateConstraints
makes sure a future call toupdateConstraintsIfNeeded
callsupdateConstraints
.setNeedsLayout
makes sure a future call tolayoutIfNeeded
callslayoutSubviews
.
setNeedsUpdateConstraints
确保将来调用updateConstraintsIfNeeded
callupdateConstraints
。setNeedsLayout
确保将来调用layoutIfNeeded
calllayoutSubviews
。
When layoutSubviews
is 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 setNeedsUpdateConstraints
is 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 setNeedsLayout
in 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
updateConstraints
method (a recommended way to change constraints, btw), callsetNeedsUpdateConstraints
, and most of the time,setNeedsLayout
after 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 setNeedsUpdateConstraints
is 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 循环图,它解释了其他行为:
- I've found out that if I use
-setNeedsLayout
instead of-setNeedsUpdateConstraints
everything work as expected, but if I change-layoutIfNeeded
with-updateConstraintsIfNeeded
, the animation won't happen.
- 我发现如果我使用
-setNeedsLayout
而不是-setNeedsUpdateConstraints
一切都按预期工作,但是如果我更改-layoutIfNeeded
为-updateConstraintsIfNeeded
,动画将不会发生。
updateConstraints
typically doesn't do anything. It just resolves constraints it doesn't apply them till layoutSubviews
is called. So animation does requires a call to layoutSubviews
.
updateConstraints
通常什么都不做。它只是解决layoutSubviews
在调用之前不应用它们的约束。所以动画确实需要调用layoutSubviews
.
- setNeedsLayout calls also -updateContraints method
- 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 setNeedsUpdateConstraint
to modify constraints in the process.
不,这不是必需的。如果您的约束尚未修改,则 UIView 将跳过对updateConstraints
. 您需要显式调用setNeedsUpdateConstraint
以修改流程中的约束。
In order to call updateConstraints
you need to do the following:
要拨打电话,updateConstraints
您需要执行以下操作:
[view setNeedsUpdateConstraints];
[view setNeedsLayout];
[view layoutIfNeeded];