Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NSView subclass - drawRect: not called

I have created a NSView subclass called DAView, incorporating an array of useful methods for later re-use. This works great, however, drawRect: is never called in any classes that use DAView, nor in the class itself. Why?

Here's how DAView looks like:

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");
}

Now, if I wanted to make use of this DAView's additions/methods, I face the same problem. Everything works fine, except for drawRect:, which, as in DAView's case, is never called:

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");
}

However If I change DATableView's header to be a subclass of NSView, drawRect: is called. What am I missing?

like image 622
Pripyat Avatar asked May 25 '13 16:05

Pripyat


1 Answers

From the docs:

"The order that setWantsLayer: and setLayer: are called is important, it makes the distinction between a layer-backed view and a layer-hosting view."

"A layer-backed view is a view that is backed by a Core Animation layer. Any drawing done by the view is cached in the backing layer. You configure a layer-backed view by invoking setWantsLayer: with a value of YES. The view class automatically creates a backing layer for you (using makeBackingLayer if overridden), and you must use the view class’s drawing mechanisms. When using layer-backed views you should never interact directly with the layer. Instead you must use the standard view programming practices."

"A layer-hosting view is a view that contains a Core Animation layer that you intend to manipulate directly. You create a layer-hosting view by instantiating a Core Animation layer class and supplying that layer to the view’s setLayer: method. After doing so, you then invoke setWantsLayer: with a value of YES. This method order is crucial. When using a layer-hosting view you should not rely on the view for drawing, nor should you add subviews to the layer-hosting view. The root layer (the layer set using setLayer:) should be treated as the root layer of the layer tree and you should only use Core Animation drawing and animation methods. You still use the view for handling mouse and keyboard events, but any resulting drawing must be handled by Core Animation."

Since you are supplying your own layer, rather than wanting Cocoa to create one for you, try it this way around.

    // 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;

Or alternatively, accept the one Cocoa gives you and don't create your own.

like image 111
Steve Waddicor Avatar answered Oct 03 '22 23:10

Steve Waddicor