Reputation: 7721
For cocoa, I have an NSTableView set to be view based. When a row is selected, the text fields change their color to white. How do I keep it black?
I should also note that the Highlight is set to Source List (it does the same thing on Regular).
Unselected row
Selected Row
I was hoping for something similar to the state config for iOS:
This was suggested in WWDC 2011 Session 120 but it's a bit delayed so I'm not going to use it. It may work for someone else though.
- (void)tableViewSelectionDidChange:(NSNotification *)notification
{
[tableView enumerateAvailableRowViewsUsingBlock:^(NSTableRowView *rowView, NSInteger row){
NSTableCellView *cellView = [rowView viewAtColumn:0];
if(rowView.selected){
cellView.textField.font = [NSFont boldSystemFontOfSize:14];
}else{
cellView.textField.font = [NSFont systemFontOfSize:14];
}
}];
}
Upvotes: 18
Views: 11735
Reputation: 9131
In macOS 11 or higher, the .dark
and .light
background styles are deprecated. But you can use .emphased
instead:
override var backgroundStyle: NSView.BackgroundStyle {
willSet {
textField.textColor = newValue == .emphasized ? .labelColor : .secondaryLabelColor
}
}
In the example, .labelColor
is the selected color, and .secondaryLabelColor
the unselected color.
Upvotes: 0
Reputation: 1259
For my Swift app none of the above seemed to quite work correctly. This method handles the NSTableView losing focus correctly and when the window is not the key window but the cell is still selected.
Within the NSTableCellView
subclass use the following:
override var backgroundStyle: NSView.BackgroundStyle {
willSet {
if newValue == .dark {
title.textColor = NSColor.white
} else {
title.textColor = NSColor.labelColor
}
}
}
Upvotes: 2
Reputation: 229
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)
}
}
Upvotes: 3
Reputation: 2647
Based on @sabes's answer, I created this NSTextFieldCell
subclass which you can use to set your custom text colors when a row is selected or deselected. You can set the subclass of the relevant text field cell in IB.
@interface SNBlueTextFieldCell : NSTextFieldCell
@end
@implementation SNBlueTextFieldCell
- (void)setBackgroundStyle:(NSBackgroundStyle)backgroundStyle {
[self setTextColor:(backgroundStyle==NSBackgroundStyleDark ? [NSColor blackColor] : [NSColor blueColor])];
}
@end
Upvotes: 1
Reputation: 927
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.
Upvotes: 18
Reputation: 335
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];
}
}
Upvotes: 14
Reputation: 10159
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.
Upvotes: 17