Swift,Cocoa:使用NSGraphicsContext时NSView属性无法更新是什么原因?
核心原因
绘制逻辑的层级冲突
CALayer的渲染优先级从下到上为:backgroundColor → contents。你在draw(_:)方法中获取CGContext执行绘制时,所有绘制结果会被自动写入layer的contents属性,相当于在backgroundColor上覆盖了一层不透明内容,此时你修改layer.backgroundColor的效果会被完全遮挡,看起来就像属性更新失效。
如果你注释掉获取context的guard语句,draw(_:)没有执行自定义绘制,不会生成覆盖用的contents,修改backgroundColor的效果自然能正常显示。未开启layer-backed视图导致setNeedsDisplay失效
NSView默认不会自动创建layer,你没有在TestView中手动设置wantsLayer = true,所以所有对self.layer的操作默认都是无效的,同时系统的绘制刷新触发逻辑也会异常,这是你调用setNeedsDisplay没反应的核心原因。手动调用draw(_:)的逻辑错误
draw(_:)是系统绘制流水线的回调方法,不应该手动调用。手动调用时系统不会为你准备有效的绘制上下文,也不会同步刷新layer的缓存内容,进一步导致属性更新不生效。
修复步骤
- 首先给TestView添加开启layer-backed的逻辑:
class TestView: NSView { override init(frame frameRect: NSRect) { super.init(frame: frameRect) wantsLayer = true } required init?(coder: NSCoder) { super.init(coder: coder) wantsLayer = true } // 原有代码保持不变 }
- 删掉ViewController中mouseDown里手动调用
draw()的代码,放开setNeedsDisplay的注释 - 不要混合使用两种渲染逻辑,二选一即可:
- 只用layer属性:删除
draw(_:)中的上下文绘制代码,直接在r/g/b属性的didSet回调中修改layer.backgroundColor,不需要触发重绘 - 只用上下文绘制:不要修改
layer.backgroundColor,所有渲染逻辑都通过CGContext实现,修改r/g/b属性后调用setNeedsDisplay触发重绘即可
- 只用layer属性:删除
内容的提问来源于stack exchange,提问作者chemFour
相关产品推荐
相关产品推荐

