Coloring rows in View based NSTableview
Asked Answered
R

4

19

I have a view based nstableview. I want to color entire row based on some condtion for which I have used code below

- (NSTableRowView *)tableView:(NSTableView *)tableView rowViewForRow:(NSInteger)row 
{
    NSTableRowView *view = [[NSTableRowView alloc] initWithFrame:NSMakeRect(1, 1, 100, 50)];

    [view setBackgroundColor:[NSColor redColor]];
    return view;;
}

The delegate method is called, but table doesn't seem to be using NSTableRowView returned by delegate method.

Main aim here is coloring entire row based on some condition. Whats wrong in above implementation?

Reverent answered 6/6, 2012 at 8:34 Comment(1)
To set backgroundColor, you need to use - (void)tableView:(NSTableView *)tableView didAddRowView:(NSTableRowView *)rowView forRow:(NSInteger)row in your NSTableViewDelegate. See my more detailed answer below.Pontefract
P
40

For anyone else who hits this and wants a custom NSTableRowView backgroundColor, there are two approaches.

  1. If you don't need custom drawing, simply set rowView.backgroundColor in - (void)tableView:(NSTableView *)tableView didAddRowView:(NSTableRowView *)rowView forRow:(NSInteger)row in your NSTableViewDelegate.

    Example:

    - (void)tableView:(NSTableView *)tableView
        didAddRowView:(NSTableRowView *)rowView
               forRow:(NSInteger)row {
    
        rowView.backgroundColor = [NSColor redColor];
    
    }
    
  2. If you do need custom drawing, create your own NSTableRowView subclass with desired drawRect. Then, implement the following in NSTableViewDelegate:

    Example:

    - (NSTableRowView *)tableView:(NSTableView *)tableView
                    rowViewForRow:(NSInteger)row {
        static NSString* const kRowIdentifier = @"RowView";
        MyRowViewSubclass* rowView = [tableView makeViewWithIdentifier:kRowIdentifier owner:self];
        if (!rowView) {
            // Size doesn't matter, the table will set it
            rowView = [[[MyRowViewSubclass alloc] initWithFrame:NSZeroRect] autorelease];
    
            // This seemingly magical line enables your view to be found
            // next time "makeViewWithIdentifier" is called.
            rowView.identifier = kRowIdentifier; 
        }
    
        // Can customize properties here. Note that customizing
        // 'backgroundColor' isn't going to work at this point since the table
        // will reset it later. Use 'didAddRow' to customize if desired.
    
        return rowView;
    }
    
Pontefract answered 9/10, 2013 at 0:5 Comment(6)
Does this work if you are using a cell based table view? I'm under the impression it does not, but I just wanted to verify.Jerrold
You are my time Saver! Thank for sharing how to use rowViewForRow delegate.Tented
Thanks! This worked perfectly. Before I found this I was a little confused as to how to add my subclassed row, but this works wonders.Jesselyn
This is the best solutionLozier
When I do this, all of the cell view's subviews draw with the old background color, and the color I set only draws around them.Desrochers
didAddRowView will not work if you reload single rows. If you set any style there it will not update.Adrenocorticotropic
R
1

Finally it worked as below

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

{
        NSView *cellView = (NSView*) [tableView makeViewWithIdentifier:[tableColumn identifier] owner:[tableView delegate]];
        CALayer *viewLayer = [CALayer layer];
        [viewLayer setBackgroundColor:[[NSColor redcolor] CGColor]];
        [cellView setWantsLayer:YES]; 
        [cellView setLayer:viewLayer];
        return cellView;
    }

Please note.. u need to convert nscolor to cgcolor which you can find in https://gist.github.com/707921 or http://forrst.com/posts/CGColor_Additions_for_NSColor-1eW

Reverent answered 7/6, 2012 at 3:32 Comment(1)
This approach is a hack -- it sets the individual cell views to be layer-hosting (which isn't always what you want), and it doesn't change the style of the entire row. See my answer on this page for a documented approach.Pontefract
E
0

If you watch the presentation on view based tableviews from WWDC 2011, you'll see that the main idea is to create the views in Interface Builder, and then obtain them from there. Something like:

[tableView makeViewWithIdentifier:@"GroupRow" owner:self];

Once you have obtained the view, just set its properties and return it.

Notice in this example that it has its own identifier, so remember to set that, but you can also used automatic identifiers.

I don't know if a direct link to the WWDC will work, but the main page is here: https://developer.apple.com/videos/wwdc/2011/ and if you search for "View Based NSTableView Basic to Advanced", you'll find it. It is well worth watching.

Electrotonus answered 6/6, 2012 at 8:47 Comment(2)
i will be using bindings to populate data to the rowReverent
yeah.. i want to use view basedReverent
M
0

I re-wrote the layer approach. In Swift 3.2

func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {

    let greenCell = self.tableview.make(withIdentifier: "green", owner: self)
    let layer:CALayer = CALayer()
    layer.backgroundColor = NSColor.green.cgColor

    greenCell?.wantsLayer = true
    greenCell?.layer = layer

    return greenCell

}

Don't forget to change the Identifier of the cell according to your storyboard, and in the code identifier "green". And surely, the background color if you want.

Maryammaryann answered 26/4, 2017 at 14:32 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.