调用 setNeedsLayout 或 setNeedDisplay 的场合



我读过一些文章,说setNeedsLayout和layoutIfNeed有什么区别,而我关注的是:

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的调用才会实际使用这些值并更改布局。这就是为什么你只需要把它放在动画块中(不过把它全部放在块里并没有错)。

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

所以:

  1. 您无需同时调用这两个方法即可立即进行布局。如果视图布局已经失效(在大多数情况下是这样),那么layoutIfNeeded就足够了。但请注意,setNeedsLayout就像在内部将布尔值设置为 true 一样微不足道,因此调用它没有害处,只是一种预防措施。因此,同时调用两者更安全。不过,单独打电话给setNeedsLayout不会"立即"做任何事情。

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

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

我找到了我想问的问题,什么时候应该调用setNeedLayout,什么时候不应该调用。 由于调用setNeedLayout的目的是调用layoutSubviews,所以对于以下情况,我不必调用setNeedLayout

  • 调整视图大小
  • 添加子视图用户
  • 滚动 UIScrollView
  • (layoutSubviews在UIScrollView及其超级视图上调用)
  • 用户轮换其设备
  • 更新视图的约束

最新更新