Моя цель - иметь ячейки динамического размера в UICollectionView
.Кроме того, когда прокручиваемый contentWidth
из UICollectionView
меньше, чем bounds
из Коллекции, я хочу, чтобы элементы были в центре коллекции.
Подход к настоящему моменту:
Я пытаюсь сделать это максимально чистым способом.У меня есть собственный размер UICollectionViewCells
, где Auto-Layout может определить размер ячейки на основании контентов контента.Для этого мои ячейки переопределяют функцию preferredLayoutAttributesFitting
, возвращая соответствующую ширину для их содержимого.
Мой пользовательский подкласс UICollectionViewFlowLayout
использует эту информацию о ширине, предоставленную UICollectionViewCell
, для правильного размера ячеек.
Единственные методы, переопределенные в моем пользовательском UICollectionViewFlowLayout
:
layoutAttributesForItem(at...)
layoutAttributesForElementsIn(rect...)
shouldInvalidateLayout(forBoundsChange...)
Динамический размер UICollectionViewCells
работает безупречно.
Проблема:
При использовании этого подхода у меня нет предварительных знаний оРазмер каждой ячейки (каждая может быть разной).Я хотел бы реализовать метод UICollectionView
delegate
, чтобы обеспечить вставку для центрирования моего контента в представлении коллекции.Для этого, я думаю, я должен реализовать и переопределить
collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets
Проблема заключается в том, что метод inset вызывается на ранней стадии процесса компоновки, где я не знаю, что contentSize
этобудет определен во время макета.
Вот набор различных методов макета для одного полного прохода макета в порядке их запуска:
prepare started
prepare finished
layoutAttributesForElementsInRect started
layoutAttributesForElementsInRect finished
layoutAttributesForElementsInRect started
layoutAttributesForElementsInRect finished
layoutAttributesForElementsInRect started
layoutAttributesForElementsInRect finished
prepare started
insetForSectionAt 0 called <--- The datasource has knowledge of the presence of cells but the cells themselves are not yet dequeued
prepare finished
layoutAttributesForElementsInRect started
layoutAttributesForItemAt [0, 0] started
layoutAttributesForItemAt [0, 0] finished
layoutAttributesForItemAt [0, 1] started
layoutAttributesForItemAt [0, 1] finished
layoutAttributesForItemAt [0, 2] started
layoutAttributesForItemAt [0, 2] finished
layoutAttributesForElementsInRect finished
layoutAttributesForElementsInRect started
layoutAttributesForItemAt [0, 0] started
layoutAttributesForItemAt [0, 0] finished
layoutAttributesForItemAt [0, 1] started
layoutAttributesForItemAt [0, 1] finished
layoutAttributesForItemAt [0, 2] started
layoutAttributesForItemAt [0, 2] finished
layoutAttributesForElementsInRect finished
prepare started
prepare finished
layoutAttributesForElementsInRect started
<--- At this point Cells DO return valid sizes through Autolayout
layoutAttributesForItemAt [0, 0] started
layoutAttributesForItemAt [0, 0] finished
layoutAttributesForItemAt [0, 1] started
layoutAttributesForItemAt [0, 1] finished
layoutAttributesForItemAt [0, 2] started
layoutAttributesForItemAt [0, 2] finished
layoutAttributesForElementsInRect finished
Для одного прохода макета:выполняется несколько вызовов различных методов макета, но только в самом конце информация о размере из Auto-layout доступна из разных ячеек для передачи в макет.
Я заметил, что функция делегата sectionInset
вызывается рано, до того, как ячейки были должным образом удалены из очереди и им разрешено запускать ограничения Autolayout.Следовательно, невозможно сообщить правильное значение для вставки во время ее вызова.
При таком подходе можно ли принудительно вызвать вызов для пересчета sectionInsetAt
после прохода макета или следуетЯ полностью изменил технику?
То, что я пробовал:
Я пытался запросить collectionViewLayout
collectionViewContentSize
из функции делегата insetForSectionAt
.К сожалению, это не может быть использовано во время этапа макета, так как макет в данный момент выполняется.Вызывает сбой с ошибкой:
[CollectionView] An attempt to update layout information was detected while already in the process of computing the layout (i.e. reentrant call). This will result in unexpected behaviour or a crash. This may happen if a layout pass is triggered while calling out to a delegate. UICollectionViewFlowLayout instance is (<App.ViewportToolbarFlowLayout: 0x7f8a5261add0>)
Я пытался использовать метод collectionView
contentSize
, чтобы получить размер во время выполнения метода делегата insetForSectionAt
, но он не обеспечиваетправильные данные в тот момент, когда они выполняются в процессе компоновки.