Какие переменные UI меняются при скролле коллекции в iOS
Что проверяют
Понимаете ли вы, что скролл в UIKit это изменение bounds.origin у UIScrollView, а не перемещение ячеек. Следом обычно спрашивают, где безопасно реагировать на скролл и как не уронить частоту кадров.
Как отвечать
Что меняется при скролле UICollectionView:
contentOffset: главная переменная. Это то же самое, чтоbounds.originколлекции, поэтому frame ячеек в её координатах остаётся прежним, сдвигается видимое окно;contentSize: при обычном скролле постоянен, меняется при подгрузке новой страницы или после инвалидации layout;adjustedContentInset: учитывает safe area, большой заголовок навбара иUIRefreshControl. Из-за негоcontentOffsetв самом верху бывает отрицательным;- состояние жеста:
isTracking,isDragging,isDecelerating, скорость черезpanGestureRecognizer.velocity(in:); - набор видимого:
visibleCellsиindexPathsForVisibleItems. Ячейка, ушедшая за край, попадает в пул переиспользования, потом проходитprepareForReuse()иcellForItemAt. Вокруг этого вызываютсяwillDisplayиdidEndDisplaying, аUICollectionViewDataSourcePrefetchingзаранее просит данные.
На каждое изменение bounds коллекция спрашивает shouldInvalidateLayout(forBoundsChange:). Базовый UICollectionViewLayout возвращает false. Возвращать true нужно для липких заголовков и параллакса, и тогда layoutAttributesForElements(in:) пересчитывается на каждом кадре.
Реагируют на скролл в scrollViewDidScroll(_:), доводку до страницы делают в scrollViewWillEndDragging(_:withVelocity:targetContentOffset:), где targetContentOffset можно переписать. В SwiftUI с iOS 18 для этого есть onScrollGeometryChange и onScrollPhaseChange.
Где спотыкаются
Говорят, что при скролле меняются frame ячеек. Это ошибка в модели: меняется окно просмотра.
Делают тяжёлую работу в scrollViewDidScroll. Он приходит на каждом кадре, на ProMotion до 120 раз в секунду, и декодирование картинок там даёт видимые рывки.
Не сбрасывают состояние в prepareForReuse(). В переиспользованной ячейке остаётся старое выделение, а асинхронная загрузка дописывает картинку в ячейку, которая уже показывает другой элемент.