【问题标题】:Framework uses drawRect:; I need to use it on a layer-backed NSView. How to update?框架使用drawRect:;我需要在支持层的 NSView 上使用它。如何更新?
【发布时间】:2018-08-23 14:44:51
【问题描述】:

根据 NSView 的 drawRect: 的文档

如果您的应用使用其图层对象管理内容,请使用 updateLayer 方法更新您的图层,而不是覆盖此方法。

我有一个NSView,其中包含框架提供的子视图,它们都使用drawRect: 进行绘制。这个框架提供的视图是NSView 的子视图,我需要一个层。因为我的框架提供的视图是支持层的视图的后代,所以通常不会调用drawRect:,尤其是在窗口处于活动或非活动状态的情况下(视图需要更新以反映其(非)活动状态)。

当然,如果我使包含视图不支持图层,则当窗口处于活动或非活动状态时会发生更新。

在不将框架修改为自定义分支的情况下,确保drawRect: 在我的框架提供的视图中出现的最佳途径是什么?

谢谢。

2018 年 8 月 25 日编辑:

看起来诀窍是将层次结构中的一个视图设置为,例如[view setCanDrawSubviewsIntoLayer:YES,根据文档,它使用所有子视图的drawRect: 将它们的绘图添加到它自己的层。然而,这似乎只在 10.13 中有效,并且在 10.14 测试版中被打破。我将继续寻找潜在的 API 更改,除非这是 10.14 测试版错误。

由于问题仍未解决,因此尚未真正得到解答。

【问题讨论】:

  • 我想你可能会感到困惑。我不确定您到底在问什么,但父视图的 -drawRect: 方法负责调用/触发/调用其子视图的 -drawRect:。每个视图(无论层与否)都会在它发生变化时被绘制出来,而 Cocoa 中的神奇显示管理器会合成生成的图像。换句话说,needsDisplay 状态(最终导致新的-drawRect: 消息)独立于其父视图和子视图。
  • 我并不是建议drawRect: 负责子视图。我的意思是,如果我有一个通过drawRect: 在层支持的视图 A 上绘制的视图 B,那么我的视图 B 当我聚焦或取消聚焦窗口时,没有调用它的drawRect:。层支持视图的后代也成为层支持,因此引用的文档表明drawRect: 不会被调用。如果我没有为视图 A 添加图层,那么我的视图 B drawRect: 会在需要时调用。
  • 哦,我想我现在明白了。那么为什么您的自定义NSView 不能简单地观察其窗口的NSWindowDidBecomeMainNotification 和'NSWindowDidResignMainNotification` 通知并向其所有子视图发送needDisplay=YES 消息?看起来很简单(而且无害)。
  • 我没有自定义NSView,除非我想分叉框架。如果我能找到一个通用的解决方案,那么我认为 PR 会受到欢迎,但主要是我试图找到行为差异的原因和解决方案。破解它以使其工作,找出区别并以正确的方式进行操作是有区别的。我不是付费专业人士,所以我更愿意了解正在发生的事情,而不是暴力破解。
  • 为了清楚起见,您不必继承 NSView任何 对象都可以观察通知并采取一些行动(例如,您的窗口控制器)。如果您认为框架控件在层支持的视图中行为不端,那么一定要提交错误报告。但我怀疑其中涉及黑客行为......

标签: cocoa calayer nsview drawrect


【解决方案1】:

不覆盖-wantsUpdateLayer 以返回true 的支持图层的视图仍然使用-drawRect: 绘制自己。您引用的一些文档使用“应该”来表示“应该,以获得最佳性能”。这不是必需的,只是推荐。

视图通常不会仅仅因为包含的窗口更改了键或主状态而重绘自己。您必须将它们标记为需要显示。或者框架应该这样做。

我怀疑当您的视图没有图层支持时它起作用的原因是您将视图标记为需要更新。由于非图层支持的视图使用 Painter 模型(从后到前)绘制到窗口的后备存储中,如果您的视图重绘自身,那么任何子视图都必须在视图的绘图之上重绘自己。

如果框架的视图需要在窗口的键/主状态发生变化时重绘,那么它们应该观察相关通知并将自己设置为需要显示。如果他们不这样做,那就是框架错误。您可以通过将它们标记为需要自己显示来解决它。

【讨论】:

  • 有问题的框架是MMTabBarView,并使用 NSButton 和 NSButtonCell 后代,它们知道如何在窗口处于活动或不活动状态时重新绘制自己,即它们被自动标记为脏。但是,在图层支持的视图上时,这似乎不会自动发生。有趣的是,我对原始问题所做的编辑有效,但仅限于 10.13。尽管您的建议/怀疑很有道理,但我会再深入研究一下。
  • 你对窗口的显示机制做了什么奇怪的事情(比如关闭autodisplay或显式显示)?您能否在一个简单的测试应用中重现(以消除您的应用可能正在做的任何其他事情)?
  • 现在我有点被撕裂了......务实的方法和对观察采取的行动非常有效,因为它应该。它让我继续前进,鉴于您为层支持的行为提供了很好的解释,我应该将您的答案标记为已接受。 James Bucanek 提出了同样的建议,但没有发布答案,所以我不确定这里的礼仪......
  • 看起来 MMTabBarView 有一个演示应用程序,您可以对其进行调整以具有支持层的容器视图。此外,4 天前有一个大更新,提交日志包括“窗口非活动窗口时的正确外观”。也许这是固定的。
  • 是的,我的 PR,在我将它与支持图层的视图一起使用之前,它工作得很好。我会接受你的回答,因为我认为除了务实的回答之外,你还解释了根本原因。谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-06-07
  • 1970-01-01
  • 2020-08-23
  • 2015-05-22
  • 1970-01-01
  • 2018-08-17
  • 1970-01-01
相关资源
最近更新 更多