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

187 views Asked by At

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.

3

There are 3 answers

0
James Bucanek On BEST ANSWER

(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.

1
James Bucanek On

I actually thought of a possibly-less-hacky solution: Add an opaque subview to NSTableRowView that completely fills its bounds and draw whatever you're trying to draw in that subview.

0
Nuzhdin Vladimir On

Subclass NSTableRowView add override isOpaque

Swift:

override var isOpaque: Bool {
    get {
        return false
    }
    set {
        
    }
}

Obj-C:

- (BOOL)isOpaque {
   return NO;
}

Take in a consideration that there are a lot of drawings. Like:

override func drawBackground(in dirtyRect: NSRect) {
override func drawSelection(in dirtyRect: NSRect) {
override func drawSeparator(in dirtyRect: NSRect) {
and more...