使用 setNeedsLayout 动画约束更改

Posted

技术标签:

【中文标题】使用 setNeedsLayout 动画约束更改【英文标题】:Animating constraints changes with setNeedsLayout 【发布时间】:2019-02-18 11:19:21 【问题描述】:

动画约束变化的标准方法是。

// Change constraints like:
someConstraint.constant = 100 

UIView.animate(withDuration: 0.25) 
    view.layoutIfNeeded()

但是我在看WWDC 2015 session on multitasking on iPad and at the end,它说不要在动画块中使用layoutIfNeeded,而是使用setNeedsLayout。但是我一直认为这意味着布局在运行循环的后期发生,因此在动画块之外。也许它记得它是在动画块中调用的?

我尝试在我的代码中将layoutIfNeeded 替换为setNeedsLayout,它似乎有效。这只是巧合吗?我们实际上应该使用setNeedsLayout 为自动布局更改设置动画?

【问题讨论】:

那些特定的 cmets 是(或者,我应该说,似乎是)在大小变化期间与动画严格相关。如果您通过点击按钮(例如)来更改约束,您确定没有看到差异吗?将您的持续时间更改为 2.0 并查看它是否真的动画超过 2 秒,例如一个不错的、缓慢的“滑动”到新位置。 【参考方案1】:

layoutIfNeeded() 的文档指出:

使用此方法强制视图立即更新其布局。使用自动布局时,布局引擎会根据需要更新视图的位置以满足约束的变化。使用接收消息的视图作为根视图,该方法从根开始布局视图子树。如果没有待处理的布局更新,则此方法退出而不修改布局或调用任何与布局相关的回调。

setNeedsLayout() 的文档指出:

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

setNeedsLayout() 将视图的所有子视图的布局推迟到 runloop 的下一个周期,从而将所有更改合并到适当的时间,而不是回避该过程并强制布局立即发生。是的,您应该在 UIView.animate 函数中使用 setNeedsLayout() 而不是 layoutIfNeeded()。尽可能做一个好公民。

【讨论】:

这并没有说明任何关于动画的内容

以上是关于使用 setNeedsLayout 动画约束更改的主要内容,如果未能解决你的问题,请参考以下文章

traitCollectionDidChange 中更新的约束无效

使用平移手势平滑地更改动画约束

使用 Swift 动画约束更改(第二项)?

如何在 Swift 中使用 layoutIfNeeded() 不为特定约束更改设置动画?

自定义布局中约束更改的动画 UICollectionView 项目

如果约束是使用 VFL 以编程方式创建的,如何为约束更改设置动画?