A view-based NSTableView
with rows that have dynamic heights doesn't resize its rows when the table view size is changed. This is a problem when the row height is derived from the table view's width (think text blocks that fills a column and wraps thus extending the row size).
I've been trying to get NSTableView
to resize its rows whenever it changed size but have experienced little success:
enumerateAvailableRowViewsUsingBlock:
, some of the non-visible rows doesn't get resized and thus were shown with the old height when the user scrolls and reveal these rows.Anybody can help?
This is where I detect the table view size change - in the table view's delegate:
- (void)tableViewColumnDidResize:(NSNotification *)aNotification
{
NSTableView* aTableView = aNotification.object;
if (aTableView == self.messagesView) {
// coalesce all column resize notifications into one -- calls messagesViewDidResize: below
NSNotification* repostNotification = [NSNotification notificationWithName:BSMessageViewDidResizeNotification object:self];
[[NSNotificationQueue defaultQueue] enqueueNotification:repostNotification postingStyle:NSPostWhenIdle];
}
}
Whereas the following is the handler of the notification posted above, where the visible rows get resized:
-(void)messagesViewDidResize:(NSNotification *)notification
{
NSTableView* messagesView = self.messagesView;
NSMutableIndexSet* visibleIndexes = [NSMutableIndexSet new];
[messagesView enumerateAvailableRowViewsUsingBlock:^(NSTableRowView *rowView, NSInteger row) {
if (row >= 0) {
[visibleIndexes addIndex:row];
}
}];
[messagesView noteHeightOfRowsWithIndexesChanged:visibleIndexes];
}
The alternative implementation that resizes all rows looks like this:
-(void)messagesViewDidResize:(NSNotification *)notification
{
NSTableView* messagesView = self.messagesView;
NSIndexSet indexes = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0,messagesView.numberOfRows)];
[messagesView noteHeightOfRowsWithIndexesChanged:indexes];
}
Note: This question is somewhat related to View-based NSTableView with rows that have dynamic heights but is more focused towards responding to the table view's size change.
I just went through this exact problem. What I did was monitor the NSViewBoundsDidChangeNotification for the scroll view's content view
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(scrollViewContentBoundsDidChange:) name:NSViewBoundsDidChangeNotification object:self.scrollView.contentView];
and in the handler, get the visible rows and call noteHeightOfRowsWithIndexesChange:. I disable animation while doing this so the user doesn't see the rows wiggle during the resize as view's come into the table
- (void)scrollViewContentBoundsDidChange:(NSNotification*)notification
{
NSRange visibleRows = [self.tableView rowsInRect:self.scrollView.contentView.bounds];
[NSAnimationContext beginGrouping];
[[NSAnimationContext currentContext] setDuration:0];
[self.tableView noteHeightOfRowsWithIndexesChanged:[NSIndexSet indexSetWithIndexesInRange:visibleRows]];
[NSAnimationContext endGrouping];
}
This has to perform quickly so the table scrolls nicely but its working very well for me.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With