How to change NSTextField text color on row selection?

Override NSTableCellView and add this method to change the text color when the cell is selected.

- (void) setBackgroundStyle:(NSBackgroundStyle)backgroundStyle
{
    NSTableRowView *row = (NSTableRowView*)self.superview;
    if (row.isSelected) {
        self.textField.textColor = [NSColor blackColor];
    } else {
        self.textField.textColor = [NSColor whiteColor];
    }

}

There is no need for custom code to accomplish that.

Just set the color of the label to "label color" in Interface Builder. The automatic white/black thing only works if the label has the "Control Text Color" set and is in an NSTableCellView.


I came up with a different solution. Subclassing NSTableCellView would have been fine if Cocoa supported @IBOutletCollection. Because then I could have one Cell subclass that has an array of all NSTextFields in the cell. But since I had many kinds of cells with varying numbers of NSTextFields I didn't like this option. Instead, I took a look at Apple's documentation for the backgroundStyle property in NSTableCellView.

The default implementation automatically forwards calls to all subviews that implement setBackgroundStyle: or are an NSControl, which have NSCell classes that respond to backgroundStyle.

If my TextFields implement setBackgroundStyle then they should get notified when the cell selection changes. However, this forwarding of the background style is not recursive. Because my NSTextFields were within NSStackViews they were not getting the message. To get around this, I just wrote an extension to implement setBackgroundStyle on all NSViews. It just forwards the message on. Lastly, I added an extension to NSTextField to also implement this method. From this extension, I change the text color and call super. This solution is also nice because no subclasses are needed. No subclasses of NSTableCellView or of NSTextField.

Adding this functionality to all views and to all NSTextFields could cause issues with NSTextFields that are not within NSTableViews changing color unexpectedly. But so far, only the ones within my TableViews/OutlineViews are changing color and thats exactly what I was looking for. If you see textfields changing color that you don't expect, you may want to subclass NSTextField and implement a setBackgroundStyle override only on that subclass instead of adding it to all NSTextFields.

The code in Swift 3 I used is pasted below.

extension NSView {
    func setBackgroundStyle(_ newValue: NSBackgroundStyle) {
        for view in self.subviews {
            view.setBackgroundStyle(newValue)
        }
    }
}

extension NSTextField {
    override func setBackgroundStyle(_ newValue: NSBackgroundStyle) {
        switch newValue {
        case .dark:
            self.textColor = NSColor.controlLightHighlightColor
        case .light, .lowered, .raised:
            self.textColor = NSColor.labelColor
        }
        super.setBackgroundStyle(newValue)
    }
}

Depending on why you need to do this, there are 2 approaches.

You can subclass NSTableRowView and override -[NSTableRowView interiorBackgroundStyle] to return NSBackgroundStyleLight. This will tell the cells that they are on a light background and to draw dark text, which will be black.

The other way is to subclass NSTableCellView and override -[NSTableCellView setBackgroundStyle:] and set the colors yourself there.