保持 NSScrollView 固定
Posted
技术标签:
【中文标题】保持 NSScrollView 固定【英文标题】:Keep NSScrollView pinned down 【发布时间】:2012-09-06 08:20:56 【问题描述】:我在 NSScrollView 中有一个 NSTableView。 NSTableView 的内容是通过绑定到绑定到 CoreData ManagedObjectContext 的 NSArrayController 来提供的。 NSTableView 的新行只是添加到并且永远不会删除或重新排序。
我希望将 NSTableView(或分别称为 NSScrollView)固定在底部,以便添加到表格中的新行立即可见。此外,这只会发生在 NSTableView 滚动到底部而不是当用户向上滚动以查看其他行时。
我目前正在使用以下代码
- (void)tableView:(NSTableView *)tableView didAddRowView:(NSTableRowView *)rowView forRow:(NSInteger)row
NSInteger numberOfRows = [tableView numberOfRows];
NSLog(@"row: %lu, %lu numberOfRows ", row, numberOfRows);
if (row == numberOfRows-1)
[tableView scrollRowToVisible:numberOfRows - 1];
到目前为止,这有效,但仅在窗口处于活动状态时。当窗口处于非活动状态时,不会调用 didAddRowView 方法,直到窗口再次变为活动状态。因此 NSTableView 不会立即向下滚动。由于 NSTableView 也通过 CoreData 绑定填充,我不知道在插入新项目后我可以手动触发滚动的任何一点。此外,didAddRowView 委托方法经常被调用(例如,当手动滚动表格时)并且只有在插入新项目后才真正需要向下滚动,这使得解决方案更加不优雅。
当应用程序处于活动状态和非活动状态时,我是否可以直接挂接到插入过程或 NSScrollView 以向下滚动到底部?
编辑: 为了完成或如果@rdelmar 的解决方案对您不起作用,我将有问题的 NSTableView 子类化并在 reloadData 方法中实现了这个
- (void) reloadData
[super reloadData];
NSInteger numberOfRows = [self numberOfRows];
NSRange rowsInRect = [self rowsInRect:self.superview.bounds];
NSInteger lastVisibleRow = rowsInRect.location + rowsInRect.length;
if (lastVisibleRow == numberOfRows-1)
[self scrollRowToVisible:numberOfRows - 1];
一旦在 ArrayController 中接收到新项目并应将其添加到表中,就会调用 reloadData 方法。在调用超类的 reloadData 之后,这会检查 TableView 是否滚动到底部(TableView 的最后一行是在 superview 中可见的最后一行 - 因此是周围的 NSScrollView)。如果是这样,它会向下滚动。如果没有,用户可能会向上滚动以查看表格的某些内容,并且不希望它自动向下滚动。
【问题讨论】:
您如何将新数据添加到您的核心数据数据库中?它是在用户操作下,还是通过服务器下载或类似的方式自动更新。 【参考方案1】:我认为你应该可以使用 NSManagedObjectContext 通知,NSManagedObjectContextObjectsDidChangeNotification。创建一个自定义 NSTableView 类并为该通知添加一个观察者:
@implementation 自定义表格
-(void)awakeFromNib
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(scrollTable:) name:NSManagedObjectContextObjectsDidChangeNotification object:nil];
-(void)scrollTable:(NSNotification *) aNote
if ([[aNote.userInfo allKeys] containsObject:@"inserted"])
[self scrollRowToVisible:self.numberOfRows -1];
else
NSLog(@"It was not an insertion");
【讨论】:
问题在于 ArrayController 的 addObject(或任何其他添加/插入方法)没有被调用,因为它直接绑定到 CoreData ManagedObjectContext。否则我猜你的解决方案将是正确的选择 您如何向核心数据添加新数据? 行得通,谢谢。虽然,当您有很多此类表时,我发现了一种可能更适合的不同方法。它涉及在 TableView 的 reloadData 方法中挂钩更新。在我的测试过程中,这被调用的频率较低,我不确定在某些情况下滚动 NSManagedObjectContextObjectsDidChangeNotification 是否会在 TableView 应该滚动但尚未插入新项目的情况下不会提供计时问题。您的解决方案似乎有效,我接受它作为答案。或者,我已经用我的想法更新了我的问题。以上是关于保持 NSScrollView 固定的主要内容,如果未能解决你的问题,请参考以下文章