Создайте расширяемый UICollectionView, используя композиционные макеты и различимые источники данных в iOS 16.
Создание динамических ячеек Table View или Collection View — это проблема, с которой в какой-то момент столкнулось большинство разработчиков iOS. От использования estimatedRowHeight
до создания пользовательских UICollectionViewLayout
— установка динамических размеров для UICollectionViewCell
s требует реализации множества методов — и я всегда возвращался к кодам рецептов — несмотря на введение композиционных макетов.
К счастью, на WWDC 2022 Apple значительно улучшила свою структуру UIKit. В iOS 16 ячейки Table View и Collection View теперь могут автоматически изменять размер в зависимости от содержимого с помощью свойства selfSizingInvalidation
, которое включено по умолчанию.
Чтобы изменить размер ячейки вручную/программно — мы можем вызвать функцию invalidateIntrinsicContentSize()
. Если вы хотите изменить размер ячейки без анимации — вызовите функцию invalidateIntrinsicContentSize()
внутри UIView.performWithoutAnimation
.
Теперь, когда мы узнали об этом приятном обновлении, давайте создадим наше современное iOS-приложение для просмотра коллекций.
В следующих разделах мы создадим расширяемое представление коллекции, используя функции iOS 16, не полагаясь на перезагрузку элементов или создание пользовательских ячеек.
Для непосвященных: в iOS 15 в Diffable Data Sources появился новый способ обновления ячеек без замены существующих ячеек. Это работает через функцию reconfigureItems
.
Строительные блоки
- Создайте представление коллекции с помощью композиционных макетов
- Добавьте фиктивные данные. В нашем случае мы будем передавать нашему представлению «Коллекция» массив фильмов (с подробностями описания) через источник дифференцируемых данных.
- Разверните и сверните ячейки представления коллекции при выборе. В нашем случае мы покажем и скроем детали фильма.
Давайте начнем.
Настройка нашей модели данных
Мы будем хранить данные в классе Movie
, как показано ниже:
Для простоты этого примера мы установили фильм name
в качестве уникального идентификатора. Флаг showDetails
будет использоваться для развертывания и свертывания представления коллекции.
Section
в приведенном выше коде — это перечисление, которое неявно соответствует Hashable
. Он содержит два значения, обозначающих два раздела в нашем представлении коллекции.
Настройка представления нашей коллекции
Вот код для настройки макета и конфигурации UICollectionView
:
Оставьте в стороне //1
и //2
(которые предназначены для настройки diffable источника данных), остальная часть кода настраивает наше представление коллекции.
Начнем с того, что макет List
был представлен в iOS 14 и построен на основе композиционных макетов, чтобы обеспечить дизайн, подобный TableView. В приведенном выше коде мы используем его для установки нашего стиля конфигурации, который затем передается композиционному макету, который в конечном итоге передается инициализатору UICollectionView
.
Теперь давайте посмотрим на наш dataSource
.
Настройка нашего дифференцируемого источника данных
Вот код нашей функции makeDataSource()
:
В приведенном выше коде многое происходит, и если создание современных представлений коллекций для вас в новинку, вот несколько выводов, на которых следует сосредоточиться:
- Структура
UICollectionView.CellRegistration
была представлена в iOS 14. И она неявно заботится о регистрации ячеек при передаче внутри структурыdequeueConfiguredReusableCell
. Итак, попрощайтесь с регистрацией ячеек с помощью идентификаторов. UICollectionViewListCell
— это конкретный класс, который обеспечивает стиль ячеек, подобныйUITableView
. Мы вызвали функциюdefaultContentConfiguration
для этой ячейки. После получения этой конфигурации мы устанавливаем текст и описание метки ячейки на основе логики логического флага.- Затвор
cellProvider
внутриUICollectionViewDiffableDataSource
аналогиченto collectionView(_:cellForItemAt:)
Теперь, когда мы настроили наш источник данных, вот наши фиктивные данные:
Перенастройка элементов представления коллекции
Чтобы создать расширяемую ячейку представления коллекции, мы просто инвертируем значение showDetails
внутри метода делегата didSelectItem
:
Остальная логика понятна.
Выход
Вот последнее приложение в действии:
Другим примером может быть добавление текстового поля в ячейку представления коллекции и просмотр того, как оно автоматически расширяется в зависимости от типа.
Вы можете найти полный исходный код в этом GitHub Repository.
Спасибо за прочтение.