Keep same NSTableView scrolled position while inserting rows

ⅰ亾dé卋堺 提交于 2019-12-24 10:57:42

问题


I've got a view-based NSTableView showing a timeline of messages/informations. Row heights are variable. New messages are regularly added at the top of the table by using insertRows:

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

While the user stays at the top of the table, the messages keep being inserted at the top, pushing down the existing ones: a usual behavior in this context.

Everything works ok, except that if the user has scrolled down, the new inserted messages shouldn't make the table scroll.

I want the tableView to stay where it is while the user scrolls or if the user has scrolled down.

In other words, the tableView should only be pushed down by new inserted rows if the top row is 100% visible.

I've tried to give the illusion of the table not moving by quickly restoring its location like this:

// 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)

But it doesn't behave as I want. I've tried many combinations but I think I'm not understanding something about the relation between the clip view, the scroll view and the table view.

Or maybe I'm in the XY-problem zone and there's a different way to get this behavior?


回答1:


Forget the scroll view, clip view, contentView, documentView and focus on the table view. The bottom of the visible part of the table view shouldn't move. You might have missed the flipped coordinate system.

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

I didn't test "the tableView to stay where it is while the user scrolls".



来源:https://stackoverflow.com/questions/41965201/keep-same-nstableview-scrolled-position-while-inserting-rows

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!