Как определить, какие NSCollectionViewItems действительно видны - PullRequest
0 голосов
/ 31 марта 2019

Я использую NSCollectionView, который показывает изображения, которые мне нужно визуализировать в фоновом режиме. Этот рендеринг занимает значительное время (например, от 100 мс до более секунды).

Я использую обычную схему потока (NSCollectionViewFlowLayout) с плитками одинакового размера NSCollectionViewItem.

Как только collectionView запускается, он создает гораздо больше экземпляров элементов (плиток), чем фактически вписывается в текущий вид. Например, если в поле зрения помещается 6 плиток, запрашивается около 20 плиток. Я начинаю процесс рендеринга для каждой созданной плитки. Как только изображение было визуализировано, плитка получает уведомление, что, в свою очередь, приводит к обновлению ее вида.

Теперь, когда происходит рендеринг, пользователь может прокрутить вниз, например, до последних 6 плиток. Это создает проблему производительности:

В очереди все еще много визуализаций для плиток, которые еще не были видны и не будут видны в ближайшее время (они были пропущены пользователем, когда он прокрутил их непосредственно до конца). CollectionView, теперь запрашивающий представления для теперь видимых последних 6 плиток, отбросит 6 из своих ранее выделенных, 4 из которых, возможно, уже были визуализированы и помечены как отбрасываемые в любом случае, поэтому только 2 из оставшихся 16 плиток в очереди рендеринга будут уведомили, что они не понадобятся и будут удалены из очереди. И вновь видимые 6 плиток с конца будут добавлены в очередь рендеринга.

Это означает, что до того, как пользователь начнет видеть какие-либо изображения, с которых он был прокручен, необходимо будет отрендерить еще 14 изображений, даже если они не отображаются в области содержимого текущего представления коллекции.

Как я могу оптимизировать это, чтобы, когда пользователь прокручивал, я немедленно начинал рендерить самые новые видимые NSCollectionViewItem с? Кажется, что ни одна из функций делегата не помогает с этим. Даже такие функции, как visibleItems, возвращают не только видимые, но и все функции, выделенные collectionView, включая 14 невидимых.

Я мог бы при добавлении элементов в очередь всегда вставлять их в начало, а не добавлять их в конец очереди. Это также не помогло бы, потому что тогда, когда первоначально collectionView запрашивает 20 плиток, я в конечном итоге должен был сначала рендерить 20-ю плитку, и, таким образом, в итоге не отображал никаких визуализаций до тех пор, пока не было визуализировано 14 невидимых.

1 Ответ

0 голосов
/ 31 марта 2019

Документация для -[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. Можно использовать таймер, чтобы периодически проверять, какие элементы видны, и перемещать их вперед.очереди.Его не следует использовать для принятия решения о том, добавлять ли элементы в очередь, потому что, если таймер срабатывает слишком рано после создания объекта плитки, он еще не будет добавлен в представление, что приведет к большей задержке дорендеринг начинается.Поэтому я считаю, что лучше всего добавлять элементы в средство визуализации, как только он узнает, что они могут быть необходимы, но измените порядок очереди, как только станет ясно, какие элементы будут видны, а какие нет.

...