插入行时保持相同的 NSTableView 滚动位置

aya*_*aio 1 macos cocoa nstableview nsscrollview

我有一个基于视图的 NSTableView 显示消息/信息的时间线。行高是可变的。新消息会定期添加在表的顶部使用insertRows

NSAnimationContext.runAnimationGroup({ (context) in
    context.allowsImplicitAnimation = true
    self.myTable.insertRows(at: indexSet, withAnimation: [.effectGap])
})
Run Code Online (Sandbox Code Playgroud)

当用户停留在表格的顶部时,消息继续插入顶部,将现有的推下:在这种情况下的常见行为。

一切正常,除了如果用户向下滚动,新插入的消息不应该使表格滚动

我希望 tableView 在用户滚动时或用户向下滚动时保持原位。

换句话说,如果顶行是 100% 可见的tableView 应该只被新插入的行向下推。

我试图通过像这样快速恢复它的位置来给人一种桌子不动的错觉:

// we're not at the top anymore, user has scrolled down, let's remember where
let scrollOrigin = self.myTable.enclosingScrollView!.contentView.bounds.origin
// stuff happens, new messages have been inserted, let's scroll back where we were
self.myTable.enclosingScrollView!.contentView.scroll(to: scrollOrigin)
Run Code Online (Sandbox Code Playgroud)

但它并不像我想要的那样。我尝试了很多组合,但我认为我不了解剪辑视图、滚动视图和表格视图之间的关系。

或者,也许我在 XY 问题区,有一种不同的方式来获得这种行为?

Wil*_*eke 6

忘记滚动视图、剪辑视图、内容视图、文档视图并专注于表格视图。表格视图可见部分的底部不应移动。您可能错过了翻转坐标系。

NSPoint scrollOrigin;
NSRect rowRect = [self.tableView rectOfRow:0];
BOOL adjustScroll = !NSEqualRects(rowRect, NSZeroRect) && !NSContainsRect(self.tableView.visibleRect, rowRect);
if (adjustScroll) {
    // get scroll position from the bottom: get bottom left of the visible part of the table view
    scrollOrigin = self.tableView.visibleRect.origin;
    if (self.tableView.isFlipped) {
        // scrollOrigin is top left, calculate unflipped coordinates
        scrollOrigin.y = self.tableView.bounds.size.height - scrollOrigin.y;
    }
}

// insert row
id object = [self.arrayController newObject];
[object setValue:@"John" forKey:@"name"];
[self.arrayController insertObject:object atArrangedObjectIndex:0];

if (adjustScroll) {
    // restore scroll position from the bottom
    if (self.tableView.isFlipped) {
        // calculate new flipped coordinates, height includes the new row
        scrollOrigin.y = self.tableView.bounds.size.height - scrollOrigin.y;
    }
    [self.tableView scrollPoint:scrollOrigin];
}
Run Code Online (Sandbox Code Playgroud)

我没有测试“当用户滚动时 tableView 保持原位”。