【发布时间】:2018-05-18 07:48:13
【问题描述】:
我看过一些文章,说setNeedsLayout和layoutIfNeeded有什么区别,而我关注的是:
1.如果我想立即布局,是否需要将这两个方法一起调用,因为我多次看到这种组合
2。我什么时候需要调用 setNeedsLayout?据我了解,如果我更改视图的框架,它将在下一个周期更新布局,我不必显式调用 setNeedsLayout
【问题讨论】:
我看过一些文章,说setNeedsLayout和layoutIfNeeded有什么区别,而我关注的是:
1.如果我想立即布局,是否需要将这两个方法一起调用,因为我多次看到这种组合
2。我什么时候需要调用 setNeedsLayout?据我了解,如果我更改视图的框架,它将在下一个周期更新布局,我不必显式调用 setNeedsLayout
【问题讨论】:
这些东西的工作原理是通过失效来消除冗余。如果需要布局,视图将包含信息。
所以调用setNeedsLayout 只会将一些内部布尔值needsLayout 设置为true。一旦layoutIfNeeded 被调用,它将检查这个布尔值
if needsLayout {
needsLayout = false
doMagic() // Calls layoutSubviews at some point
}
之所以这样设计,是因为多次调用可能会使布局无效,但我们只想布局一次或尽可能少地布局。
在大多数情况下,您不需要致电setNeedsLayout,因为大多数更改已经为您完成了这项工作。例如,您可以更改约束值并为您完成失效。您只需致电layoutIfNeeded,您的观点就会更新。为了更正确,您甚至不需要致电layoutIfNeeded,因为它会在下一个周期为您执行此操作。但是,如果您希望更改动画并且需要在动画块中执行此操作,则需要调用它。
myViewConstraint.constant = 40.0 // Will already call setNeedsLayout
UIView.animate(withDuration: 0.3, animations: {
myView.layoutIfNeeded()
})
所以改变约束只会改变视图应该如何布局的信息。只有对layoutIfNeeded 的调用才会真正使用这些值并更改布局。这就是为什么你只需要把它放在动画块中(虽然把它全部放在块中并没有错)。
公平地说,已经有一些变化,现在默认情况下(您可以禁用它)动画方法已经自行布局您的视图,因此您可以使用更少的代码进行操作,但这不是目前的重点。
所以:
您不需要立即同时调用这 2 个方法来布局。如果视图布局已经失效(在大多数情况下),那么layoutIfNeeded 就足够了。但请注意,setNeedsLayout 就像在内部将布尔值设置为 true 一样微不足道,因此调用它没有害处,只是一种预防措施。所以调用两者更安全。不过,单独调用 setNeedsLayout 不会“立即”执行任何操作。
希望您永远不需要致电setNeedsLayout。在一些复杂的情况下,您需要显式地使布局无效,并且存在一些可能的 UI 错误。在所有其他情况下,这将为您完成。但请注意,如果您遇到需要称其为“它将在下一个周期更新布局”的情况,则将不正确。在视图布局失效之前,它根本不会布局。
我不确定setNeedDisplay 适合您的问题(仅在您的标题中),但这个问题的工作方式相同,但有点复杂。它将使其内容无效并强制其重绘,调用drawRect。这必须在其绘制管道期间发生,而不仅仅是任何时候,因此您可能不会显式调用它来重绘。如果你什么都不做(可能会崩溃),因为它没有可以利用的上下文。如果您覆盖drawRect 并调整视图大小,它将尝试缓存您绘制的内容并使用contentMode 调整绘图大小。默认情况下,它设置为scaleToFill,这意味着您的内容将随着视图大小的变化而被拉伸。您需要致电setNeedDisplay 以便再次调用您的drawRect,并且您可以相应地重绘内容。
【讨论】:
我找到了我想问的问题,什么时候应该调用 setNeedLayout,什么时候不应该。由于调用setNeedLayout的目的是调用layoutSubviews,所以对于以下情况,我不必调用setNeedLayout
【讨论】: