NSTableView: How to resize text in cells correctly

2k views Asked by At

I need to increase the font size in an NSTableView (view based mode) to allow for better readability in some kind of a presentation of my app.

Changing the font works fine within - (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row:

    NSTableCellView *cellView = [tableView makeViewWithIdentifier:identifier owner:self];
    [cellView.textField setFont:self.tableFont];
    cellView.textField.stringValue = rowData[row];
    [cellView.textField setNeedsDisplay:YES];

I also update the rowHeight with - (CGFloat) tableView:(NSTableView *)tableView heightOfRow:(NSInteger)row, this also works:

- (CGFloat) tableView:(NSTableView *)tableView heightOfRow:(NSInteger)row {
    if (self.tableFont) {
        NSLog(@"Setting row height to %.1f", [self.tableFont pointSize]+8);
        return [self.tableFont pointSize] + 8;
    }
    return [NSFont systemFontSize] + 8;
}

(There are probably way more elegant ways to determine the correct height)

Now, here is my issue: I do see the font being changed. I also see the rowHeight being changed (nicely visible as I use alternate row colouring). But the text within the cells seems to be clipped to its old height (probably 17 pixels), so with larger font sizes I only see the top of the writing, then some white space, and then again the the upper part of the next row.

For me it looks like some view clips the NSTableViewCell to its old height... I already played with setting the frames and bounds to different values, but this didn't change anything:

    NSRect rect = [cellView.textField frame];
    rect.origin.y = 1;
    rect.size.height = [self.tableFont pointSize] + 6;
    [[cellView.textField cell] setFrame:rect];
    [cellView.textField setFrame:rect];
    [cellView.textField setBounds:rect];
    [cellView.textField setNeedsDisplay:YES];
    [cellView setFrame:rect];
    [cellView setBounds:rect];
    [cellView setNeedsDisplay:YES];

I am kind of lost here... I guess I am missing something simple, but I have no idea where to look...

Thanks, Jan

1

There are 1 answers

3
Wil Shipley On

You have to make sure your constraints are set so your NSTextField can grow automatically when the autolayout pass is hit—there shouldn’t be ANY constraint on the height of the NSTextField, because it’ll have an intrinsic height that’s based on the fontSize.

Also, in view-based mode, there is also a misfeature where the cellView’s ‘textField' and ‘imageView’ outlets are treated specially: in NSTableCellView will actually sets the frame DIRECTLY on its textField and imageView in its -viewWillDraw, ignoring horizontal constraints and breaking their own rules on layout. (This is filed as Radars 11713245 & 15359487).

Here’s the code I use to work around this misfeature in my custom NSTableCellView class for 10.8 and 10.9. Note in my case I only needed to reset the x offsets of the fields:

#pragma mark NSView

- (void)viewWillDraw;
{
    const NSRect imageViewFrame = self.imageView.frame, textFieldFrame = self.textField.frame;

    [super viewWillDraw]; // NSTableCellView in  source list-mode outline view will apply custom metrics and positioning here by calling -_doStandardRowSizeStyleLayout, which manually calls setFrame: on the textField and imageView, screwing up our autolayout...

    // ...so put the x offsets back the way we really wanted them, dammit (Radar 11713245, 15359487)
    if (imageViewFrame.origin.x != self.imageView.frame.origin.x)
        [self.imageView setFrameOrigin:(NSPoint){imageViewFrame.origin.x, self.imageView.frame.origin.y}];

    if (textFieldFrame.origin.x != self.textField.frame.origin.x)
        [self.textField setFrameOrigin:(NSPoint){textFieldFrame.origin.x, self.textField.frame.origin.y}];
    if (textFieldFrame.size.width != self.textField.frame.size.width)
        [self.textField setFrameSize:(NSSize){textFieldFrame.size.width, self.textField.frame.size.height}];
}