调用 setNeedsLayout 或 setNeedDisplay 的场合

whi*_*vin 3 ios swift

我已经阅读了一些关于 setNeedsLayout 和 layoutIfNeeded 之间有什么区别的文章,而我关注的是:

1.如果我想立即布局,是否需要同时调用这两个方法,因为这种组合我见过很多次了

2.什么时候需要调用setNeedsLayout?据我了解,如果我更改视图的框架,它将在下一个周期更新布局,我不必显式调用 setNeedsLayout

Mat*_*lak 6

这些东西的工作原理是通过失效来消除冗余。视图将包含是否需要布局的信息。

所以调用setNeedsLayout只会将一些内部布尔值设置needsLayouttrue. 一旦layoutIfNeeded被调用,它将检查这个布尔值

if needsLayout { 
    needsLayout = false
    doMagic() // Calls layoutSubviews at some point
}
Run Code Online (Sandbox Code Playgroud)

之所以这样设计,是因为多次调用可能会使布局无效,但我们希望只布局一次或尽可能少地布局。

在大多数情况下,您不需要调用,setNeedsLayout因为大多数更改已经为您完成了。例如,您可以更改约束值并为您完成失效。您只需要打电话layoutIfNeeded,您的观点就会更新。更准确地说,你甚至不需要打电话,layoutIfNeeded因为它会在下一个周期为你做这件事。但是,如果您希望更改动画,则需要调用它,并且需要在动画块中执行此操作。

myViewConstraint.constant = 40.0 // Will already call setNeedsLayout
UIView.animate(withDuration: 0.3, animations: {
    myView.layoutIfNeeded()
})
Run Code Online (Sandbox Code Playgroud)

所以改变约束只会改变关于视图应该如何布局的信息。只有调用layoutIfNeeded才会实际使用这些值并更改布局。这就是为什么你只需要把它放在动画块中(虽然把它全部放在块中并没有错)。

公平地说,有一些变化,现在默认情况下(您可以禁用它)动画方法已经自己布局您的视图,因此您可以使用更少的代码来完成,但这不是目前的重点。

所以:

  1. 您不需要同时调用这 2 种方法来立即进行布局。如果视图布局已经失效(在大多数情况下),那么layoutIfNeeded就足够了。但请注意,这setNeedsLayout与在内部将布尔值设置为 true 一样微不足道,因此调用它没有任何害处,只是一种预防措施。所以调用两者更安全。但是,setNeedsLayout单独呼叫不会“立即”执行任何操作。

  2. 希望您永远不需要调用setNeedsLayout. 在一些复杂的情况下,您需要明确地使布局无效,并且存在一些可能的 UI 错误。在所有其他情况下,这将为您完成。但请注意,如果您遇到需要调用“它将在下一个周期更新布局”的情况,则将不成立。在视图布局失效之前,它根本不会布局。

我不确定setNeedDisplay你的问题在哪里(它只在你的标题中),但这个问题的工作方式相同,但有点复杂。它将使其内容无效并强制它重绘,调用drawRect. 这必须在其绘制管道期间发生,而不仅仅是在任何时候,因此您可能不会明确调用它来重绘。如果你什么都不做,就会发生(可能是崩溃),因为它没有上下文可以借鉴。如果您覆盖drawRect并调整视图的大小,它将尝试缓存您绘制的内容并用于contentMode调整绘图的大小。默认情况下,它设置为scaleToFill这意味着您的内容将随着视图大小的变化而拉伸。您将需要呼叫setNeedDisplay才能drawRect再次被呼叫,并且您可以相应地重绘内容。