How to invert text colour of selected NSTableView row

You don't say what view or view hierarchy you're using for your cells. You also don't say how or where you're setting the text fields' color or to what color, specifically.

When a row is selected, the row automatically computes its interiorBackgroundStyle. It also sets the backgroundStyle of the cell view if it responds to -setBackgroundStyle: or is an NSControl with a cell which responds to that.

If your cell view is an instance of NSTableCellView, it forwards the background style to all of its subviews which meet the same criteria. If you use a different container view as your cell view and you want the background style forwarded along like this, you would have to implement that yourself in your view class.

An NSTextField's cell (an NSTextFieldCell) responds to -setBackgroundStyle: and so has its background style set automatically by the above mechanisms. The text field cell will automatically change its text color to white if its textColor is one of the standard control colors (e.g. NSColor.controlTextColor()), but won't do so if you assign a non-standard color. So, if you're setting a specific color for your text, you are responsible for changing that when the background style changes.

You can use a subclass of NSTableCellView and add a property observer (didSet) for the backgroundStyle property. That can change the text field's textColor depending on the style that was set. For example, you can use your custom color if the background style is not .Dark or use the normal text field color NSColor.controlTextColor() if it is .Dark (so that the text field will actually display it as white).

You could also use a subclass of NSTextFieldCell for your text field and do the same sort of thing. Or override drawInteriorWithFrame(_:inView:) to draw with a different text color depending on the background style.


With the help of Ken's response (above) I was able to get it to work. Here's a rough draft that does what I want it to:

import Cocoa

class CustomTextFieldCell: NSTextFieldCell {

    // When the background changes (as a result of selection/deselection) switch appropriate colours
    override var backgroundStyle: NSBackgroundStyle {
        didSet {
            if (backgroundStyle == NSBackgroundStyle.Dark) {
                if self.textColor == NSColor.redColor() {
                    self.textColor = NSColor.yellowColor()
                }
            } else if (backgroundStyle == NSBackgroundStyle.Light) {
                if (self.textColor == NSColor.yellowColor()) {
                    self.textColor = NSColor.redColor()
                }
            }
        }
    }

    // When the colour changes, switch to a better alternative for the cell's current background
    override var textColor: NSColor? {
        didSet {
            if let colour = self.textColor {
                if backgroundStyle == NSBackgroundStyle.Dark {
                    if self.textColor == NSColor.redColor() {
                        self.textColor = NSColor.yellowColor()
                    }
                } else if backgroundStyle == NSBackgroundStyle.Light {
                    if (self.textColor == NSColor.yellowColor()) {
                        self.textColor = NSColor.redColor()
                    }
                }
            }
        }
    }

}

If I set my CustomTextFieldCell as the custom class for my table view cell in the identity inspector, it works. I needed to add a property observer for textColor as well so that rows which are currently highlighted get the same treatment. I may alter it now so that it's not hard coded but this demonstrates the concept.

Thanks Ken.