cocoanstableviewnstableviewcellnstablecellview

Autolayout in an NSView being used as a cell for NSTableView


I am trying to build an NSTableView similar to how Things does it's layout. Things 2.0 -- (c) CulturedCode

I assume what they are doing is using an NSTableView with a custom-drawn NSTableCell -- or perhaps it's an NSSegmentedControl. I am attempting to go down the NSTableCell route. I attempted to subclass an NSTableCellView and draw a custom cell (this is all in the init method for testing);

- (id)init {
    self = [super init];
    if (self) {
        _checkbox = [[NSButton alloc] init];
        [_checkbox setButtonType:NSSwitchButton];

        _textview = [[NSTextView alloc] init];

        [self addSubview:_checkbox];
        [self addSubview:_textview];

        [self setTranslatesAutoresizingMaskIntoConstraints:NO];
        NSDictionary *views = NSDictionaryOfVariableBindings(_checkbox, _textview);

        [self addConstraints:
                [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[_checkbox]-[_textview]|"
                                                        options:0
                                                        metrics:nil
                                                          views:views]];
    }

    return self;
}
@end

Seems pretty self-explanatory, but it doesn't actually work. I am getting errors on constraints not being able to be satisfied. Is it not possible to use autolayout inside a subclassed NSTableCellView?


Solution

  • It is possible although you have to introduce some additional code to the table view controller:

    - (CGFloat)tableView:(NSTableView *)tableView heightOfRow:(NSInteger)row
    {
    NSTableCellView *rowView = [self.tableView makeViewWithIdentifier: RVIssueSelectionTableRowViewContentKey owner: self];
    
    [rowView setObjectValue: yourDataObject]; // or update your cell with the according data the way you prefer
    [rowView setNeedsLayout: YES];
    [rowView layoutSubtreeIfNeeded];
    
    return [rowView fittingSize].height;
    }
    

    This will cause the cell to update it's layout and you can return it's desired height. Because this call can be kind of expensive you should cache the calculated cell height. This answer has been taken from another SO answer which I could not find right now (will update the solution when I've found it). Your error messages for the constraints are generated because you force the cell to have a height of x (through the table view datasource methods). But your constraints want to set the height of the cell so they are satisfied. Both at the same time can not work.