在图层托管视图上调用setNeedsDisplay:YES不会重绘视图

时间:2010-09-05 21:38:49

标签: cocoa core-animation

我在自定义NSView子类中设置了这样的图层托管视图:

[self setLayer:rootLayer];
[self setWantsLayer:YES];

在每个子图层上调用setNeedsDisplay后,我将所有子图层添加到图层树中。每个图层的内容都由我图层委托的drawLayer:inContext方法提供。

这是我的问题:

初始化视图后,视图会正确绘制。但是,当模型发生变化并且我从视图控制器调用[myCustomView setNeedsDisplay:YES];时,drawLayer:inContext不会被调用。

我现在很困惑如何更新视图:

  • 我是否必须在图层树中的每个CALayer上调用setNeedsDisplay方法?
  • 层托管视图本身的setNeedsDisplay:YES调用是否应该触发整个图层树的重绘?

感谢您的帮助。

修改

我在NSView Class引用中找到了一些东西

  

图层支持的视图是由Core Animation图层支持的视图。视图完成的任何绘制都将缓存在背衬层中。您通过简单地调用setWantsLayer配置了一个图层支持的视图:值为YES。视图类将自动为您创建背衬层,并使用视图类的绘制机制。使用图层支持的视图时,不应直接与图层进行交互。

     

图层托管视图是一个视图,其中包含您要直接操作的Core Animation图层。您可以通过实例化Core Animation图层类的实例并使用视图的setLayer:方法设置该图层来创建图层托管视图。执行此操作后,您将调用setWantsLayer:值为YES。使用图层托管视图时,您不应该依赖视图进行绘制,也不应该将子视图添加到图层托管视图。

link to documentation

在我的情况下,我有一个图层托管视图。那么这确实意味着我必须手动触发重绘吗?我应该在自定义NSView中实现一个伪drawRect方法来调用更改的CALayers上的相应setNeedsDisplay吗?

3 个答案:

答案 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