I am trying to create a custom NSView
that hosts a CALayer
hierarchy to perform efficient display. This NSView
is then embedded within a NSTableCellView
that is displayed by a View-Based NSOutlineView
.
The problem is that whenever I expand or collapse an item, all rows are being moved, but the layer's content remains displayed at the position it was before changing the outline.
Scrolling the NSOutlineView
seems to refresh the layers and they resync with their rows at that point.
I have debugged this behavior using Instruments and it seems that the scrolling provokes a layout operation which updates the layers with a setPosition:
call that should have occured when expanding or collapsing items.
Here is some sample code for a simple layer hosting NSView
subclass.
@interface TestView : NSView
@end
@implementation TestView
- (instancetype)initWithFrame:(NSRect)frameRect
{
self = [super initWithFrame:frameRect];
CAShapeLayer* layer = [CAShapeLayer layer];
layer.bounds = self.bounds;
layer.position = CGPointMake(NSMidX(self.bounds), NSMidY(self.bounds));
layer.path = [NSBezierPath bezierPathWithOvalInRect:self.bounds].CGPath;
layer.fillColor = [NSColor redColor].CGColor;
layer.delegate = self;
self.layer = layer;
self.wantsLayer = YES;
return self;
}
@end
I have tried a lot of potential solutions to this problem but I couldn't find any interesting method that gets called on the NSView
instance that could be overriden to call [self.layer setNeedsDisplay]
or [self.layer setNeedsLayout]
. I also tried various setters on the CALayer
itself such as :
layer.autoresizingMask = kCALayerWidthSizable | kCALayerHeightSizable;
layer.needsDisplayOnBoundsChange = YES;
self.layerContentsRedrawPolicy = NSViewLayerContentsRedrawOnSetNeedsDisplay;
Can anyone help me figure out how to make this layer display properly inside a NSOutlineView
?