swiftcocoansoutlineviewnstablerowview

Can't override NSTableViewRow draw() behaviour to make transparent in NSOutlineView


I have an NSOutlineView with custom NSTableViewRows used throughout.

I have overridden the draw method on the NSTableViewRow:

override func draw(_ dirtyRect: NSRect) {}

...so it should never draw anything. However, rows are occasionally solid black, and occasionally clear. I can't work out a pattern to when.

If I do put something in the draw function, it will be drawing over the black when it occurs, I can't seem to clear the black in the draw function, other than by filling with a solid colour.

To clear I have tried:

let context = NSGraphicsContext.current?.cgContext
context?.clear(dirtyRect)

and

NSColor.clear.setFill()
dirtyRect.fill(using: .copy)

If I look in the Debug View Hierarchy I can clearly see that it is the NSTableViewRow itself that is black.

I have tried setting wantsLayer and setting the backgroundColor of the layer in the draw function but that has no effect.

Can anyone explain where this black fill may be coming from and where it lives!

The only way I managed to ensure it wasn't there was to use:

override var wantsUpdateLayer: Bool { get { return true } }

...which suggests that NSTableViewRow is doing something a little weird.


Solution

  • (copied from comments now that we've discovered a workaround)

    The documentation for NSTableRowView states that it "is responsible for displaying attributes associated with the row, including the selection highlight, and group row look." So the base row view class is clearly doing something, and the table view probably makes assumptions about it, and I would image it's tricky and highly optimized. :(

    A workaround would be to call super.draw(dirtyRect) in your draw(_:NSRect) just to let the base NSTableRowView class do whatever internal magic it needs to do, and then erase whatever it has drawn and draw over that.