View based NSTableView selection highlighting

|▌冷眼眸甩不掉的悲伤 提交于 2019-12-04 07:49:31
the_critic

I have actually just found (in the sidebar) this question, which advises to subclass NSTableRowView. I had already done that before, but it did not work. I have tried it again and quite surprisingly it works now...

Handling custom selection style in view based NSTableView

However, this answer is not very informative, so I will try to cover what I have done in order to make this work.

First of all, I implemented the following NSTableView delegate method and return nil!:

- (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row{

    return nil;

}

In order to use a view based (I guess NSTableViewRow is regarded a view based table as well...) table you HAVE TO implement this method. I am not quite sure what I might have done wrong, but without this method, my cells are not displayed!

Make sure to not let the NSTableView handle any selection by setting this property:

yourNSTableView.selectionHighlightStyle = NSTableViewSelectionHighlightStyleNone;

Okay, so now we want to set up our cells with the following delegate method:

-(NSTableRowView *)tableView:(NSTableView *)tableView rowViewForRow:(NSInteger)row{

    static NSString *cellID = @"cell_identifier";

    //use this if you want to reuse the cells
    CustomTableRowView *result = [tableView makeViewWithIdentifier:cellID owner:self];

    if (result == nil) {

        result = [[CustomTableRowView alloc] initWithFrame:NSMakeRect(0, 0, self.frame.size.width, 80)];
        result.identifier = cellID;

    }

    result.data = [tableData objectAtIndex:row];

    // Return the result
    return result;

}

Okay so now subclass NSTableRowView and implement/override the following two methods:

First we have to override setSelected: in order to make the cell redraw its background when it is selected. So here it is:

-(void)setSelected:(BOOL)selected{

    [super setSelected:selected];
    [self setNeedsDisplay:YES];

}

As mentioned earlier, we call setNeedsDisplay: in order for the cell to redraw its background.

Finally, the drawing code. Override the method drawBackgroundInRect: like this:

-(void)drawBackgroundInRect:(NSRect)dirtyRect{
    if (!self.selected) {
        [[NSColor clearColor] set];
    } else {
        [someColor set];
    }
    NSRectFill(dirtyRect);
}
Utkarsha

Use the following code in response to the NSTableViewDelegate protocol tableViewSelectionDidChange:

Get the NSTableRowView for the selected row and call the method setEmphasized on it. When setEmphasized is set to YES you get the blue highlight, when NO you get the gray highlight.

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

     NSInteger selectedRow = [myTableView selectedRow];
     NSTableRowView *myRowView = [myTableView rowViewAtRow:selectedRow makeIfNecessary:NO];
    [myRowView setSelectionHighlightStyle:NSTableViewSelectionHighlightStyleRegular];
     [myRowView setEmphasized:NO];
}

And to avoid dancing effect of blue then gray set

[_tableView setSelectionHighlightStyle:NSTableViewSelectionHighlightStyleNone];

the_critic's solution in Swift: (tested with XCode 7 beta3, Swift 2.0)

class CustomTableRowView: NSTableRowView {

    override var selected: Bool {
        willSet(newValue) {
            super.selected = newValue;
            needsDisplay = true
        }
    }

    override func drawBackgroundInRect(dirtyRect: NSRect) {
        let context: CGContextRef = NSGraphicsContext.currentContext()!.CGContext

        if !self.selected {
            CGContextSetFillColorWithColor(context, NSColor.clearColor().CGColor)
        } else {
            CGContextSetFillColorWithColor(context, NSColor.redColor().CGColor)
        }

        CGContextFillRect(context, dirtyRect)
    }

}

ViewController:

class ViewController: NSViewController, NSTableViewDelegate, NSTableViewDataSource {

    // [...]

    func tableView(tableView: NSTableView, rowViewForRow row: Int) -> NSTableRowView? {
        guard let rowView = tableView.makeViewWithIdentifier("RowView", owner: nil) as! CustomTableRowView? else {
            let rowView = CustomTableRowView()
            rowView.identifier = "RowView"
            return rowView
        }

        return rowView
    }

}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!