NSView子类 - drawRect:未调用

Pri*_*yat 4 cocoa objective-c

我创建了一个NSView名为的子类DAView,它包含了一组有用的方法,以便以后重用.然而,这种方法很有用,drawRect:从不在任何使用过的类中调用DAView,也不在类本身中调用.为什么?

这是DAView看起来像:

DAView

@interface DAView : NSView

- (id)initWithFrame:(NSRect)frame
{
    self = [super initWithFrame:frame];

    if (self)
    {
        self.backgroundColor = [NSColor clearColor];

        // Make layer-backed by default
        self.wantsLayer = YES;

        // Create a root layer
        CALayer *_rootLayer = [CALayer layer];

        _rootLayer.shouldRasterize = YES;

        _rootLayer.name = DAViewRootLayerDefaultName;

        self.layer = _rootLayer;
    }

    return self;
}

- (void)drawRect:(NSRect)dirtyRect // never called
{
    NSLog(@"Draw Rect called");
}
Run Code Online (Sandbox Code Playgroud)

现在,如果我想使用这些DAView's添加/方法,我将面临同样的问题.一切都很好,除了drawRect:,在这种DAView情况下,从来没有被称为:

DATableView

@interface DATableView : DAView

- (void)drawRect:(NSRect)dirtyRect // never called either
{
    [[NSColor grayColor] set];

    NSBezierPath *_cellSeparator = [NSBezierPath bezierPath];

    [_cellSeparator lineToPoint:dirtyRect.origin];

    [_cellSeparator closePath];

    [_cellSeparator stroke];

    NSLog(@"Draw rect");
}
Run Code Online (Sandbox Code Playgroud)

但是,如果我将DATableView标题更改为子类NSView,drawRect:则调用.我错过了什么?

Ste*_*cor 9

来自文档:

"setWantsLayer:和setLayer:被调用的顺序很重要,它区分了图层支持的视图和图层托管视图."

"图层支持的视图是由Core Animation图层支持的视图.视图完成的任何绘图都缓存在支持图层中.您可以通过调用setWantsLayer来配置图层支持的视图:值为YES. class会自动为您创建一个支持层(如果被覆盖则使用makeBackingLayer),并且必须使用视图类的绘图机制.使用图层支持的视图时,不应该直接与图层交互.而是必须使用标准视图编程实践. "

"图层托管视图是一个包含您想要直接操作的核心动画图层的视图.您可以通过实例化Core Animation图层类并将该图层提供给视图的setLayer:方法来创建图层托管视图.然后,您调用setWantsLayer:值为YES.此方法顺序至关重要.使用图层托管视图时,不应依赖视图进行绘制,也不应将子视图添加到图层托管视图.根图层(使用setLayer :)设置的图层应被视为图层树的根图层,您应该只使用Core Animation绘图和动画方法.您仍然使用视图处理鼠标和键盘事件,但必须处理任何生成的图形由Core Animation."

既然您提供自己的图层,而不是希望Cocoa为您创建一个图层,请尝试这种方式.

    // Create a root layer
    CALayer *_rootLayer = [CALayer layer];

    _rootLayer.shouldRasterize = YES;

    _rootLayer.name = DAViewRootLayerDefaultName;

    self.layer = _rootLayer;

    // Make layer-backed by default
    self.wantsLayer = YES;
Run Code Online (Sandbox Code Playgroud)

或者,接受Cocoa给你的一个,不要创建自己的.


Jon*_*hon 4

您必须将 的委托设置_rootLayerself

编辑 它对我来说如何工作:

- (id)initWithFrame:(NSRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        self.wantsLayer = YES;
        self.layer = [self makeBackingLayer];
        [self.layer setDelegate:self];
    }

    return self;
}

- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx {
    NSRect rect = self.bounds;
    rect.origin.x = 0;
    rect.origin.y = 0;
    [self drawRect:rect];
}
Run Code Online (Sandbox Code Playgroud)