我在自定义NSView
子类中设置了这样的图层托管视图:
[self setLayer:rootLayer];
[self setWantsLayer:YES];
在每个子图层上调用setNeedsDisplay
后,我将所有子图层添加到图层树中。每个图层的内容都由我图层委托的drawLayer:inContext
方法提供。
这是我的问题:
初始化视图后,视图会正确绘制。但是,当模型发生变化并且我从视图控制器调用[myCustomView setNeedsDisplay:YES];
时,drawLayer:inContext
不会被调用。
我现在很困惑如何更新视图:
setNeedsDisplay
方法?setNeedsDisplay:YES
调用是否应该触发整个图层树的重绘?感谢您的帮助。
修改
我在NSView Class引用中找到了一些东西
图层支持的视图是由Core Animation图层支持的视图。视图完成的任何绘制都将缓存在背衬层中。您通过简单地调用setWantsLayer配置了一个图层支持的视图:值为YES。视图类将自动为您创建背衬层,并使用视图类的绘制机制。使用图层支持的视图时,不应直接与图层进行交互。
图层托管视图是一个视图,其中包含您要直接操作的Core Animation图层。您可以通过实例化Core Animation图层类的实例并使用视图的setLayer:方法设置该图层来创建图层托管视图。执行此操作后,您将调用setWantsLayer:值为YES。使用图层托管视图时,您不应该依赖视图进行绘制,也不应该将子视图添加到图层托管视图。
在我的情况下,我有一个图层托管视图。那么这确实意味着我必须手动触发重绘吗?我应该在自定义NSView中实现一个伪drawRect方法来调用更改的CALayers上的相应setNeedsDisplay吗?
答案 0 :(得分:10)
在Apple的sample code信息亭式菜单中进一步研究后,我发现如果您使用的是图层托管视图,则必须自行处理由于模型更改而需要的屏幕更新。在NSView上调用setNeedsDisplay:YES
将不会执行任何操作。
那么如果必须更新视图,必须要做的就是编写像reloadData这样的方法,在其中应该在每个需要刷新的CALayer上调用setNeedsDisplay
。我仍然不确定根层上对此方法的调用是否会传播到所有子层,但我不这么认为。
我现在通过在需要重新缓存的单个CALayers上调用setNeedsDisplay
来解决问题。它没有问题。
答案 1 :(得分:2)
还有一种经常使用的做法是使用空的“drawrect”,la -(void) drawRect:(NSRect)dirtyRect {}
来帮助强制绘图,我相信通过好的view.needsDisplay = YES;
。
并且应该注意......确实发生的事情是 - 通过说NSView *view;
是layer.delegate = view;
导致在调用[layer setNeedsDisplay];
时绘制图层....通过- (void) drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx {...}
..
同样的说法......在说layer.layoutManager = view
时...后续要求[layer setNeedsLayout];
仅在实施- (void) layoutSublayersOfLayer:(CALayer *)layer {..}
方法时才会实现..
这些至关重要的概念在Apple的文档中被掩盖和散落......而且它们对于使任何东西完全无效至关重要。
答案 2 :(得分:0)
您可以通过更改视图的重绘策略来自动委派setNeedsDispay:
。您必须将NSViewLayerContentsRedrawOnSetNeedsDisplay
分配给属性layerContentsRedrawPolicy
(请参见https://developer.apple.com/documentation/appkit/nsview/1483514-layercontentsredrawpolicy)。当您将setNeedsDisplay:
发送到视图时,这将触发图层的重画:
[self setLayer:rootLayer];
[self setWantsLayer:YES];
self.layerContentsRedrawPolicy = NSViewLayerContentsRedrawOnSetNeedsDisplay;
或在Swift中:
layer = rootLayer
wantsLayer = true
layerContentsRedrawPolicy = .onSetNeedsDisplay