动画完成后如何滚动到添加到NSTableView的行

时间:2014-01-09 15:13:50

标签: macos cocoa core-animation nstableview

向NSTableView添加新行后,我想滚动到它。

当该行已添加到表的末尾时,滚动仅滚动到之前最后一行的行。我最初认为我必须等待动画完成,但这并没有解决我的问题。这是我的代码:

        [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];

我该怎么做?

2 个答案:

答案 0 :(得分:2)

我找到了解决他问题的方法,我很满意:

[_tableView insertRowsAtIndexes:indexSet withAnimation:NSTableViewAnimationEffectGap];

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

我只是将滚动请求延迟到下一个运行循环。

答案 1 :(得分:1)

我们遇到了这个问题,所以我们最终在其他动画发生时进行滚动,以便将行保留在屏幕上。您可以在动画分组中调用此代码,您可以在其中执行tableView修改。

代码如下所示:

- (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;
}