绘制矩形与布局子视图 - NSView - Cocoa touch

发布于 2024-09-24 12:10:57 字数 104 浏览 0 评论 0原文

我找不到一个合适的答案来解释这两个函数之间的区别。 每个人什么时候接到电话,其中一个与另一个有何不同?

例如,我不能只在drawrect 中布局我的视图吗?

谢谢

I can't find a decent answer to explain me the difference between these 2 functions.
when does every one gets called, and how does one different then the other ?

for example , can't I just layout my views inside drawrect ?

Thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

转瞬即逝 2024-10-01 12:10:57

如果设置了“需要布局”标志,则从 -layoutIfNeeded 调用 -layoutSubviews(使用 -setNeedsLayout,或在视图边界更改时自动) 。使用它来定位您的视图 [编辑:使用它来定位子视图]。

如果设置了“需要显示”标志(使用-setNeedsDisplay),则从-displayIfNeeded调用-drawRect:,或者如果设置则自动调用>view.contentMode = UIViewContentModeRedraw)。

-layoutIfNeeded-displayIfNeeded 都会在绘制到屏幕之前由 UIKit/CoreAnimation 自动调用;你很少需要直接打电话给他们。

您可以将子视图放置在 -drawRect: 中(您甚至可以添加子视图!),但这是不明智的:

  • 默认情况下,不会在边界更改时自动调用 -setNeedsDisplay
  • 实现 -drawRect: 会降低性能(UIKit/CoreAnimation 必须为您创建位图支持的图形上下文);仅当您需要执行自定义绘图时才这样做。
  • 您需要在-drawRect:中重绘视图。画画很贵。移动视图很便宜。
  • UIKit/CoreAnimation 可能会执行布局过程,然后进行绘图过程。 CoreAnimation 可以使用布局信息来决定需要绘制哪些视图(例如,它可以忽略被不透明子视图、离屏视图或 ClipsToBounds=YES 视图边界之外的子视图遮挡的视图;或者它只能绘制大视野)。如果在绘制过程中移动视图,CoreAnimation 可能无法正确绘制它们。

编辑:当我醒来时,还有一些更多细节:

“显示”和“绘制”之间有什么区别?显示是通过-[CALayer显示]来完成的;默认实现是(大约)

  • 如果图层的委托响应 -displayLayer:,则调用 [self.delegate displayLayer:self]-displayLayer: 应该将 layer.content 设置为(例如)CGImage,
  • 否则,如果图层的委托响应 -drawLayer:inContext:,设置一个位图支持的上下文,调用[self.delegate drawLayer:self inContext:context],并将输出保存到layer.content(输出实际上是CABackingStore,可能是私有 API)
  • 否则,请勿更改 layer.content

视图是图层的委托,因此您可以改为实现 -[MyView displayLayer:] ,并执行一些有趣的操作,例如

  • self.layer.contents = (id)([UIImage imageNamed:@" foo"].CGImage) (这大致就是 UIImageView 所做的)
  • 无操作,以防止任何“绘制”。如果您已经子类化了 UIToolbar 并希望为其提供透明背景,这可能会很有用。 (这也会阻止创建 CGContext/CABackingStore。)
  • 在不影响性能的情况下移动子视图(但由于上述原因,这仍然不是一个好主意)。

-layoutSubviews is called from -layoutIfNeeded if the "layout needed" flag was set (using -setNeedsLayout, or automatically when the view bounds changes). Use it for positioning your view [EDIT: Use it for positioning subviews].

-drawRect: is called from -displayIfNeeded if the "display needed" flag was set (using -setNeedsDisplay, or automatically if you set view.contentMode = UIViewContentModeRedraw).

Both -layoutIfNeeded and -displayIfNeeded are called automatically by UIKit/CoreAnimation before things are drawn to screen; you rarely need to call them directly.

You can position your subviews in -drawRect: (you can even add subviews!), but this is unwise:

  • By default, -setNeedsDisplay is not called automatically on a bounds change.
  • Implementing -drawRect: reduces performance (UIKit/CoreAnimation has to create a bitmap-backed graphics context for you); only do so if you need to perform custom drawing.
  • You need to redraw the view in -drawRect:. Drawing is expensive. Moving views around is cheap.
  • UIKit/CoreAnimation probably does a layout pass followed by a drawing pass. CoreAnimation can use layout information to decide what views need drawing (e.g. it could ignore views obscured by opaque subviews, off-screen views, or subviews outside the bounds of a clipsToBounds=YES view; or it could only draw a sub-rect of a large view). If you move views during the drawing pass, CoreAnimation might not draw them correctly.

EDIT: And some more detail when I'm awake:

What's the difference between "display" and "draw"? Displaying is done by-[CALayer display]; the default implementation is (approximately)

  • If the layer's delegate responds to -displayLayer:, call [self.delegate displayLayer:self]. -displayLayer: is supposed to set layer.content to (e.g.) a CGImage,
  • Otherwise, if the layer's delegate responds to -drawLayer:inContext:, set up a bitmap-backed context, call [self.delegate drawLayer:self inContext:context], and save the output to layer.content (the output is actually a CABackingStore, which is presumably a private API)
  • Otherwise, don't change layer.content.

The view is the layer's delegate, so you can implement -[MyView displayLayer:] instead, and do interesting stuff like

  • self.layer.contents = (id)([UIImage imageNamed:@"foo"].CGImage) (which is roughly what UIImageView does)
  • A no-op, to prevent any "drawing". This might be useful if you've subclassed e.g. UIToolbar and want to give it a transparent background. (This also prevents creation of the CGContext/CABackingStore.)
  • Move subviews around without the performance penalty (but it's still not a good idea for the reasons above).
画离情绘悲伤 2024-10-01 12:10:57

也许我没有所有的答案,但我可以告诉你:
- 当视图框架改变时,layoutSubviews被调用
- 当 setNeedDisplay 被调用时,drawRect 被调用

大多数时候你不会使用layoutSubviews。

可能还有其他情况,但它可以给你第一个答案^^

祝你好运

Maybe I don't have all the answers, but I can say you that :
- layoutSubviews is called when the view frame is changed
- drawRect is called when setNeedDisplay is called

Most of the time you won't use layoutSubviews.

There may be others cases, but it could give you a first piece of answer ^^

Good luck

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文