如何确定哪些NSCollectionViewItems实际可见

时间:2019-03-30 22:35:42

标签: uikit nscollectionview

我正在使用NSCollectionView,它显示需要在后台渲染的图像。渲染需要花费大量时间(例如100毫秒至一秒以上)。

我使用规则的流布局(NSCollectionViewFlowLayout)和相同大小的NSCollectionViewItem磁贴。

collectionView上线后,它将创建比实际适合当前视图的项目实例(平铺)更多。例如,如果6个图块适合视图,则要求约20个图块。我为每个创建的图块开始一个渲染过程。渲染图像后,就会通知该图块,这又会刷新其视图。

现在,在进行中的同时,用户可以向下滚动,例如到最后6个图块。这会导致性能问题:

队列中仍有许多渲染图,这些渲染图尚不可见,并且很快也将不可见(当用户直接滚动到末尾时,它们会被跳过)。现在,collectionView请求现在可见的最后6个图块的视图将丢弃其先前分配的图块中的6个,无论如何其中4个可能已经被渲染并标记为丢弃,因此渲染队列中其余16个图块中只有2个将被渲染。通知他们将不再需要它们并将其从队列中删除。从头开始新看到的6个图块将附加到渲染队列中。

这意味着,在用户开始查看其滚动到的任何图像之前,即使未在当前收藏夹视图的内容区域中显示这些图像,也必须渲染14幅图像。

如何优化此设置,以便在用户滚动时立即开始渲染最新的可见NSCollectionViewItem?似乎没有任何委托函数对此有所帮助。甚至visibleItems之类的函数不仅返回可见的函数,而且还返回collectionView分配的所有函数,包括14个不可见的函数。

我可以在将项目添加到队列时,始终将它们插入到最前面,而不是将它们附加到队列的末尾。但是,那也无济于事,因为在开始时,当collectionView要求20个图块时,我将首先渲染第20个图块,因此最终将不显示任何渲染,直到渲染了14个不可见的渲染为止。 >

1 个答案:

答案 0 :(得分:0)

-[NSCollectionView visibleItems]的文档:

  

此数组可能包含集合视图实际可见矩形之外的项目。例如,它可能包含最近可见但从视图中滚动出来的项目。要测试某个项目是否实际可见,请检查其框架矩形是否与集合视图的visibleRect相交。

因此,这是一个执行此测试的函数,仅返回实际可见的项:

- (NSArray<NSCollectionViewItem*> * _Nonnull) trulyVisibleItemsInCollectionView:(NSCollectionView*)collectionView
{
    NSMutableArray<NSCollectionViewItem*> *result = [NSMutableArray array];
    NSArray<NSCollectionViewItem *> *items = collectionView.visibleItems;
    NSRect viewRect = collectionView.visibleRect;
    for (NSCollectionViewItem *item in items) {
        if (NSIntersectsRect(item.view.frame, viewRect)) {
            [result addObject:item];
        }
    }
    return result;
}

尽管如此,这仍然使得有效管理渲染队列变得困难:

  1. 调用我的collectionView:itemForRepresentedObjectAtIndexPath:时,视图还没有添加到collectionView中,因此,现在判断该磁贴是否应安排立即渲染还为时过早。

  2. 可以使用计时器来定期检查哪些项目可见,并将其移到队列的最前面。不应使用它来决定是否将项目插入队列中,因为如果在创建tile对象之后计时器触发得太早,则不会将其添加到视图中,这将导致更多延迟,直到渲染开始。因此,我相信最好在知道可能需要添加项目后立即将其添加到渲染器中,但是,一旦清楚哪些项目是可见的,哪些项目将不可见,就对队列进行重新排序。