0

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.

Giles
  • 1,428
  • 11
  • 21
  • I don't have a suggestion, but I will note that 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 table view probably makes assumptions about it, and I would image it's probably tricky and highly optimized. :( – James Bucanek Apr 14 '18 at 18:35
  • Thank you James. Yes, it does seem that the group and selection behaviour is at work here (I reuse the same objects for group and non-group rows). I find it strange that the documented approaches to overriding default behaviour don't allow me to create the look I want - semi-transparent rows for example. – Giles Apr 16 '18 at 08:43
  • Edited title to clarify problem and goal as voted too broad. – Giles Apr 16 '18 at 09:47
  • Thinking about it a little, it might still be possible. Have you tried calling `super.draw(dirtyRect:)` (so the framework can do whatever it's going to do), then ignore that and erase everything by drawing with `clear`? – James Bucanek Apr 16 '18 at 16:49
  • Hi @JamesBucanek. Thank you so much for your help. I have returned to this and your last suggestion does indeed work. It seems a little counter-intuitive, but forcing the parent to draw, then clearing it away does the trick. Please add as an answer and I will mark it correct. – Giles May 15 '18 at 08:29
  • Hi @Giles, I actually thought of a second solution, so I posted them both. You pick the best one. – James Bucanek May 15 '18 at 17:05

3 Answers3

0

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

James Bucanek
  • 3,299
  • 3
  • 14
  • 30
0

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.

James Bucanek
  • 3,299
  • 3
  • 14
  • 30
  • Thanks James. I was actually looking to draw an alpha gradient into a floating header row. – Giles May 15 '18 at 20:54
0

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...
Nuzhdin Vladimir
  • 1,714
  • 18
  • 36