How to scroll to a line added to NSTableView after animation is complete

After adding a new row to NSTableView, I would highlight it.

When this row is added to the end of the table, the scroll only scrolls to the row that was previously the last row. At first I thought I needed to wait for the animation to finish, but this did not solve my problem. Here is my code:

        [NSAnimationContext beginGrouping];
        [_tableView insertRowsAtIndexes:indexSet withAnimation:NSTableViewAnimationEffectGap];
        [[NSAnimationContext currentContext] setCompletionHandler:^{

            // Scroll to the first inserted row

            NSUInteger firstIndex = [indexSet firstIndex];
            [_tableView scrollRowToVisible:firstIndex];

        }];
        [NSAnimationContext endGrouping];

How can i do this?

+4
source share
2 answers

I found a solution to my problem that I am satisfied with:

[_tableView insertRowsAtIndexes:indexSet withAnimation:NSTableViewAnimationEffectGap];

[[NSOperationQueue mainQueue] addOperationWithBlock:^{
    NSUInteger firstIndex = [indexSet firstIndex];
    [_tableView scrollRowToVisible:firstIndex];
}];

I just delay the scroll request until the next loop of the loop.

+1
source

, , , . , .

:

- (BOOL)scrollRowToVisible:(NSInteger)row animate:(BOOL)animate;
{
    LIClipView *const clipView = (id)_sourceListOutlineView.enclosingScrollView.contentView;
    const NSRect finalFrameOfRow = [_sourceListOutlineView rectOfRow:row];
    const NSRect clipViewBounds = clipView.bounds;

    if (NSIsEmptyRect(finalFrameOfRow) || _sourceListOutlineView.numberOfRows <= 1)
        return NO;

    const NSRect finalFrameOfLastRow = [_sourceListOutlineView rectOfRow:(_sourceListOutlineView.numberOfRows - 1)];
    if (NSMaxY(finalFrameOfLastRow) <= NSHeight(clipViewBounds))
        // The source list is shrinking to fully fit in its clip view (though it might still be larger while animating); no scrolling is needed.
        return NO;

    if (NSMinY(finalFrameOfRow) < NSMinY(clipViewBounds)) {
        // Scroll top of clipView up to top of row
        [clipView scrollToPoint:(NSPoint){0, NSMinY(finalFrameOfRow)} animate:animate];
        return YES;
    }

    if (NSMaxY(finalFrameOfRow) > NSMaxY(clipViewBounds)) {
        // Scroll bottom of clipView down to bottom of source, but not such that the top goes off-screen (i.e. repeated calls won't keep scrolling if the row is higher than visibleRect)
        [clipView scrollToPoint:(NSPoint){0, MIN(NSMinY(finalFrameOfRow), NSMaxY(finalFrameOfRow) - NSHeight(clipViewBounds))} animate:animate];
        return YES;
    }

    return NO;
}
+1

All Articles