简体   繁体   中英

NSTableRowView/NSTableCellView how to set custom color to selected row?

I am trying to implement custom row color when table row is selected.

-(void)tableViewSelectionDidChange:(NSNotification *)notification{


    NSInteger selectedRow = [_mainTable selectedRow];

    NSTableCellView *cell = [_mainTable rowViewAtRow:selectedRow makeIfNecessary:NO];

    cell.layer.backgroundColor = [NSColor redColor].CGColor;

    NSLog(@"selected");
}

But this is not working. I find that Apple documentation very confusing (maybe I am wrong). I am not experienced with Mac programming.

Can someone suggest any solution? Basically I need that selection Color to be transparent.

Solution

This should be done by subclassing NSTableRowView and then returning your subclass in with the NSTableView delegate method
-(NSTableRowView*)tableView:(NSTableView *)tableView rowViewForRow:(NSInteger)row

Subclassing NSTableRowView provides much more flexibility when modifying your row view. Returning your subclass in the NSTableView delegate method above will also automatically remove the background selection color when clicking from one row to the next (which is an open issue in the other answer provided).


Steps

First, subclass NSTableRowView and override drawSelectionInRect to change its background color when selected:

@implementation MyTableRowView

- (void)drawSelectionInRect:(NSRect)dirtyRect
{
    [super drawSelectionInRect:dirtyRect];
    [[NSColor yellowColor] setFill];
    NSRectFill(dirtyRect);
}

Next, return your subclassed row view using the rowViewForRow NSTableView delegate method:

- (NSTableRowView*)tableView:(NSTableView *)tableView rowViewForRow:(NSInteger)row
{
    static NSString* const kRowIdentifier = @"MyTableRow";
    MyTableRowView* myRowView = [tableView makeViewWithIdentifier:kRowIdentifier owner:self];
    if (!myRowView) {
        myRowView = [[MyTableRowView alloc] initWithFrame:NSZeroRect];
        myRowView.identifier = kRowIdentifier;
    }
    return rowView;
}

Using this approach, you can also easily override other elements like the separator color. To do this, override the drawSeparatorInRect method in your NSTableRowView subclass like so:

- (void)drawSeparatorInRect:(NSRect)dirtyRect
{
    // Change the separator color if the row is selected
    if (self.isSelected) [[NSColor orangeColor] setFill];
    else [[NSColor grayColor] setFill];
    // Fill the seperator
    dirtyRect.origin.y = dirtyRect.size.height - 1.0;
    dirtyRect.size.height = 1.0;
    NSRectFill(dirtyRect);
}

Resources

Overriding NSTableRowView display settings https://developer.apple.com/reference/appkit/nstablerowview

NSTableview rowViewForRow delegate method https://developer.apple.com/reference/appkit/nstableviewdelegate/1532417-tableview

first set tableview selection highlight style to

 NSTableViewSelectionHighlightStyleNone

then in your tablView delegate implement

tableView:shouldSelectRow:

and write this code inside it:

NSTableViewRow *row= [_mainTable rowViewAtRow:selectedRow makeIfNecessary:NO];
row.backgroundColor = [your color];
return YES;

read these also https://developer.apple.com/library/mac/documentation/Cocoa/Reference/NSTableViewDelegate_Protocol/index.html#//apple_ref/occ/intfm/NSTableViewDelegate/tableView:rowViewForRow :

for selection style https://developer.apple.com/library/mac/documentation/Cocoa/Reference/ApplicationKit/Classes/NSTableView_Class/index.html#//apple_ref/occ/instp/NSTableView/selectionHighlightStyle

This is to set the custom color to the selected row and also the highlighted text color. The output should look something like this,

在此输入图像描述

In the above screenshot, we are doing

  • Setting the background selected color to white

  • Adding the corner radius

  • Changing the text color to blue

  • Adding the blue stroke color

You can do a lot more customization but this answer covers above-mentioned points.

1. Start with subclassing NSTableRowView

class CategoryTableRowView: NSTableRowView {

override func drawSelection(in dirtyRect: NSRect) {
    if selectionHighlightStyle != .none {
        let selectionRect = bounds.insetBy(dx: 2.5, dy: 2.5)
        NSColor(calibratedRed: 61.0/255.0, green: 159.0/255.0, blue: 219.0/255.0, alpha: 1.0).setStroke()
        NSColor(calibratedWhite: 1.0, alpha: 1.0).setFill()
        let selectionPath = NSBezierPath(roundedRect: selectionRect, xRadius: 25, yRadius: 25)
        selectionPath.fill()
        selectionPath.stroke()
    }
  }
}

2. Return custom CategoryTableRowView() in the NSTableViewDelegate method

func tableView(_ tableView: NSTableView, rowViewForRow row: Int) -> NSTableRowView? {
      return CategoryTableRowView()
}

3. Make sure you have selectionHighlightStyle to regular in your ViewController class

override func viewDidLoad() {
     super.viewDidLoad()
     self.tableView.selectionHighlightStyle = .regular
}

4. To set the textColor, create a subclass of NSTableCellView

class CategoryCellView: NSTableCellView {

@IBOutlet weak var categoryTextField: NSTextField!

override var backgroundStyle: NSView.BackgroundStyle {
    willSet{
        if newValue == .dark {
            categoryTextField.textColor = NSColor(calibratedRed: 61.0/255.0, green: 159.0/255.0, blue: 219.0/255.0, alpha: 1.0)
        } else {
            categoryTextField.textColor = NSColor.black
        }
    }
  }
}

override the backgroundStyle property and set the desired color for the text.

Note: In my case, I have a custom cell which has a categoryTextField outlet.So to set the text color I use: categoryTextField.textColor = NSColor.black

5. Set custom class inside storyboard 在此输入图像描述

I hope this helps. Thanks.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM