Создайте расширяемый UICollectionView, используя композиционные макеты и различимые источники данных в iOS 16.

Создание динамических ячеек Table View или Collection View — это проблема, с которой в какой-то момент столкнулось большинство разработчиков iOS. От использования estimatedRowHeight до создания пользовательских UICollectionViewLayout — установка динамических размеров для UICollectionViewCells требует реализации множества методов — и я всегда возвращался к кодам рецептов — несмотря на введение композиционных макетов.

К счастью, на 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.

Спасибо за прочтение.