layoutIfNeeded 是如何使用的?
Posted
技术标签:
【中文标题】layoutIfNeeded 是如何使用的?【英文标题】:How is layoutIfNeeded used? 【发布时间】:2009-07-25 20:16:02 【问题描述】:layoutIfNeeded
何时以及如何使用?我知道当我们更改视图的布局时,我们可以调用setNeedsLayout
来更新布局,但不确定何时应该使用layoutIfNeeded
。
注意:我在实际代码中使用了layoutIfNeeded
,但忘记了它是在什么上下文中使用的。
【问题讨论】:
【参考方案1】:layoutIfNeeded
强制接收器在需要时立即布局其子视图。
假设你已经覆盖了layoutSubviews
,并且UIKit 认为你的视图出于某种原因需要布局(例如,你在处理某些用户操作时调用了setNeedsLayout
)。然后,您的自定义 layoutSubviews
方法将立即被调用,而不是在常规 UIKit 运行循环事件序列中通常调用它时(在事件处理之后,但在 drawRect:
之前)。
您可能需要在单个运行循环中调用layoutIfNeeded
的示例:
-
您调整了包含具有自定义布局的表格视图的自定义视图的大小。设置
setNeedsLayout
以便稍后调用layoutSubviews
。
控制器对象在处理用户事件时要求表格视图滚动到某个特定单元格。
您的自定义视图对layoutSubviews
中的表格视图执行一些自定义大小调整,从而更改表格视图的大小。
问题是当控制器要求表格视图滚动时(第 2 步),表格视图的边界已经过时。更新的边界稍后将仅在表视图上设置(步骤 3)。 layoutSubviews
完成后,控制器希望表格视图滚动到的内容实际上可能不可见。一个解决方案是控制器在它知道这可能发生的情况下调用layoutIfNeeded
。
【讨论】:
【参考方案2】:现在可以通过引用更新周期来描述这两种方法之间的区别。
UIView 的 setNeedsLayout 方法告诉系统您希望它在更新周期时布局和重绘该视图及其所有子视图。这是一个异步活动,因为该方法完成并立即返回,但直到稍后的时间才会真正发生布局和重绘,并且您不知道更新周期是什么时候。
相比之下,layoutIfNeeded 方法是一个同步调用,它告诉系统您想要一个视图及其子视图的布局和重绘,并且您希望它立即完成而无需等待更新周期。当对该方法的调用完成时,布局已经根据在方法调用之前记录的所有更改进行了调整和绘制。
因此,简而言之,layoutIfNeeded 表示请立即更新,而 setNeedsLayout 表示请更新,但您可以等到下一个更新周期。
【讨论】:
【参考方案3】:LayoutSubViews() - 不要直接调用,而是调用 setNeedsLayout(),如果约束基础未提供预期则覆盖 行为。
SetNeedsLayout()- 调用主线程,等待下一个绘图周期。 有利于性能。
LayoutIfNeeded() - 立即布局子视图。
【讨论】:
【参考方案4】:setNeedsLayout 实际上调用了 layoutIfNeeded,所以如果你调用 setNeedsDisplay,就没有理由调用 layoutIfNeeded。这样,setNeedsLayout 是一种调用 layoutIfNeeded 的便捷方法,它完成了繁重的工作。
【讨论】:
这不是真的。 setNeedsLayout 将标记布局视图,这将导致 layoutSubviews 在另一个 runloop 循环中被调用。调用 layoutIfNeeded 将导致 layoutSubviews 在同一个 runloop 循环中被调用。要对此进行测试,请在 layoutSubviews 中设置断点,然后在调用 setNeedsLayout 时设置断点。如果您前进一行,那么您会注意到您没有中断 layoutSubviews。但是,如果您在 layoutIfNeeded 上中断并前进一行,您会注意到您会在前进之前中断 layoutSubviews。以上是关于layoutIfNeeded 是如何使用的?的主要内容,如果未能解决你的问题,请参考以下文章
最好在更改约束之前或之后调用 .layoutIfNeeded()
Xcode8 beta 在 inputAccessoryView getter 中添加 self.view.layoutIfNeeded() 导致崩溃