Correctly resizing rows on view

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:

  • If I resize only the visible rows by querying 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.
  • If I resize all rows it becomes noticeably slow when there are a lot of rows (about 1 second delay after each window resize for 1000 rows in my 1.8Ghz i7 MacBook Air).
  • 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.

    链接地址: http://www.djcxy.com/p/49962.html

    上一篇: Qt编程人员的xaml布局介绍

    下一篇: 正确调整视图上的行大小