Создание подкласса UICollectionViewLayout с кэшированным UICollectionViewLayoutAttributes - PullRequest
0 голосов
/ 01 июня 2019

Я пытаюсь понять, как работает UICollectionViewLayout, и нашел этот пример кода.

https://developer.apple.com/documentation/uikit/uicollectionview/customizing_collection_view_layouts

В примере кода (и во всех других примерах, которые я смог найти), онимеет cachedLayoutAttributes объект и вычисляет макет всех элементов в prepare().

Я обнаружил 2 проблемы для этого шаблона.

Один из них, если количество источника данных достаточно велико, вычисление всегов методе prepare() потребуется время (и он будет пересчитан при изменении макета collectionView), поэтому он не выглядит очень эффективным.

Другая проблема заключается в том, что нет никаких шансов layoutAttributesForItem или layoutAttributesForSupplementaryView позвоните.Только layoutAttributesForElements вызывается, и кажется, что этого достаточно для размещения ячеек / дополнительных представлений.

Я читаю документацию, но она только говорит, что методы должны быть переопределены.Мое лучшее предположение состоит в том, что я должен использовать переопределить эти методы, чтобы вернуть соответствующий UICollectionViewLayoutAttributes и вызвать их из layoutAttributesForElements.Однако этот layoutAttributesForElements вызывается всякий раз, когда пользователь прокручивает UICollectionView, поэтому он также кажется не очень эффективным.

Я хочу знать, в каком случае вызывается layoutAttributesForItem и layoutAttributesForSupplementaryView и что / когда / гдеЭто лучший способ / место / время для расчета UICollectionViewLayoutAttributes, если количество источников данных огромно.

Обновление

Спасибо за комментарий.Однако похоже, что речь идет об оптимизации в цикле аннулирования.

Объекты макета, предназначенные для поддержки контекстов аннулирования, могут использовать информацию в объекте UICollectionViewLayoutInvalidationContext для оптимизации своего поведения во время цикла аннулирования.

Что означает, что UICollectionViewLayoutAttributes уже установлены и делают недействительной только необходимую часть, верно?

Итак, где я должен вычислить UICollectionViewLayoutAttributes в первый раз?Пожалуйста, дайте мне знать, если я ошибаюсь.

1 Ответ

1 голос
/ 11 июня 2019

Во-первых, если количество источника данных достаточно велико, вычисление всего в методе prepare() займет время (и будет пересчитано при изменении макета collectionView), поэтому оно не выглядит очень эффективным.

Да, это выглядит не очень эффективно.Ваша задача - сделать prepare() вычислений максимально эффективными.

Например: вычислить только часть атрибутов и вычислить больше, когда свиток изменил свою позицию, используя shouldInvalidateLayout(forBoundsChange:).Но будьте осторожны с этим методом, потому что он может сделать недействительным макет при каждой прокрутке пикселей.

prepare() метод вызывается не просто для удовольствия, он сообщает вам, что что-то изменилось, и требуется пересчет!Но информацию об изменениях получить сложно.Вы можете проверить, как IGListKit получает информацию об изменениях перед подготовкой: ссылка .

Другая проблема заключается в том, что нет никаких шансов layoutAttributesForItem или layoutAttributesForSupplementaryView позвонить.Только layoutAttributesForElements вызывается, и кажется, что этого достаточно для размещения ячеек / дополнительных представлений.

layoutAttributesForElements(in:) вызывается первым, потому что коллекция не знает о порядке ваших ячеек и дополнительныхПросмотры.Поэтому он запрашивает все атрибуты в указанном прямоугольнике.Попробуйте вставить / переместить / удалить / перезагрузить ячейки, я думаю, что layoutAttributesForItem(at:) может быть вызвано.А может и нет.Но вам не стоит беспокоиться об этом, потому что у вас уже есть кеш атрибутов.

Поскольку вы кешируете атрибуты, layoutAttributesForElements(in:) должен быть достаточно эффективным и выглядеть примерно так:

override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
    return attributes
        .reduce(into: [UICollectionViewLayoutAttributes](), { $0 += $1.filter({ $0.frame.intersects(rect) }) })
}

Я личноПредлагаем заглянуть внутрь какой-то сложной верстки с открытым исходным кодом.Вы получите гораздо больше информации о UICollectionViewLayout по сравнению с информацией из любого простого примера проекта.

...