UICollectionViewCompositionalLayout

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

В этой статье хочется познакомиться к UICollectionViewCompositionalLayout и с его помощью создать UICollectionView с прокручивающимися секциями, а затем еще немного более их кастомизировать, чтобы показать как просто с помощью UICollectionViewCompositionalLayout мы можем создавать UICollectionView, которые выглядят именно так как нам необходимо.

Статья основана на документации apple Implementing Modern Collection Views

https://developer.apple.com/documentation/uikit/views_and_controls/collection_views/implementing_modern_collection_views

Compositional layouts - это декларативный вид API, который позволяет нам создавать большие макеты путем объединения небольших групп макетов. Compositional layouts имеют иерархию, состоящую из Item, Group, Sections, and Layout.

Чтобы создать любой Compositional layouts, необходимо реализовать следующие четыре класса:

NSCollectionLayoutSize: Размеры ширины и высоты относятся к типу NSCollectionLayoutDimension, которые могут быть определены путем установки доли ширины/высоты макета (в процентах по отношению к его контейнеру) или путем установки абсолютных или расчетных размеров.

NSCollectionLayoutItem: Это ячейка нашего макета, которая отображается на экране в зависимости от размера.

NSCollectionLayoutGroup: содержит NSCollectionLayoutItem в горизонтальной, вертикальной или пользовательской формах.

NSCollectionLayoutSection: используется для инициализации секции путем передачи NSCollectionLayoutGroup. Секции в конечном итоге составляют СompositionalLayout.

Sections и items в СompositionalLayout соответствуют Sections и items класического СollectionViewDataSource. Группы, однако, не имеют эквивалента в СollectionViewDataSource и не отображают содержимое в виде элементов / ячеек. Они используются исключительно для описания расположения наших Items в рамках Section.

Давайте приступим к практике и создадим CollectionView cо скролящимися рядами. Мы увидим наскоолько просто это можно сделать с помощью СompositionalLayout по сравнению с традиционным подходом, когда для достижения подобного эффекта приходилось внедрять CollectionView в другие CollectionView.

Создадим класс ViewController, который сооответствует протоколу UICollectionViewDelegate:

class ViewController: UIViewController, UICollectionViewDelegate {

}

Добавим в него два свойства dataSource и collectionView:

var dataSource: UICollectionViewDiffableDataSource<Int, Int>! = nil
    
var collectionView: UICollectionView! = nil

Создадим класс ячейки для нашей коллекции:

class TextCell: UICollectionViewCell {
    let label = UILabel()
    static let reuseIdentifier = "text-cell-reuse-identifier"

    override init(frame: CGRect) {
        super.init(frame: frame)
        configure()
    }
    required init?(coder: NSCoder) {
        fatalError("not implemnted")
    }
}

В экстеншене зададим необходимые констрейнты:

extension TextCell {
    func configure() {
        label.translatesAutoresizingMaskIntoConstraints = false
        label.adjustsFontForContentSizeCategory = true
        contentView.addSubview(label)
        label.font = UIFont.preferredFont(forTextStyle: .caption1)
        let inset = CGFloat(10)
        NSLayoutConstraint.activate([
            label.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: inset),
            label.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -inset),
            label.topAnchor.constraint(equalTo: contentView.topAnchor, constant: inset),
            label.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -inset)
            ])
    }
}

Мы подошли непосредственно к созданию лэйаута. Вынесем его в отдельный метод:

func createLayout() -> UICollectionViewLayout {
        let layout = UICollectionViewCompositionalLayout {
            (sectionIndex: Int, layoutEnvironment: NSCollectionLayoutEnvironment) -> NSCollectionLayoutSection? in

// Для начала создаем Item. Задаем ему ширину и высоту группы, 
// в который он будет помещен. Для этого задаем widthDimension и 
// heightDimension значения .fractionalWidth(1.0) и .fractionalHeight(1.0) соответственно.
// Так же задаем у Item отступы через свойство contentInsets.
            
        let item = NSCollectionLayoutItem(
            layoutSize: NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),
                                                  heightDimension: .fractionalHeight(1.0)))
            item.contentInsets = NSDirectionalEdgeInsets(top: 10, leading: 10, bottom: 10, trailing: 10)


// Создаем Group элементы которой распологаются горизонтально. 
// Задаем ей ширину 85% ширины экрана и высоту 40% высоты экрана.
// Добавляем в Group созданный выше Item
            
        let containerGroup = NSCollectionLayoutGroup.horizontal(
            layoutSize: NSCollectionLayoutSize(widthDimension: .fractionalWidth(0.85),
                                                  heightDimension: .fractionalHeight(0.4)),
            subitems: [item])
            
// Создаем Section, передавая в инициализатор созданныую выше Group. 
// Для того чтобы секция имела взможность скролиться задаем ее свойство  
// orthogonalScrollingBehavior.
       
        let section = NSCollectionLayoutSection(group: containerGroup)
        section.orthogonalScrollingBehavior = .continuous

        return section

    }
     return layout
}

Теперь мы можем создать СollectionView, передав в инициализатор лэйаут, кторый возвращает созданный нами метод.

Вынемем создание и конфигурацию СollectionView в отдельный метод.

 func configureHierarchy() {
        collectionView = UICollectionView(frame: view.bounds, collectionViewLayout: createLayout())
        collectionView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        collectionView.backgroundColor = .systemMint
        view.addSubview(collectionView)
        collectionView.delegate = self
 }

И вызовем его во viewDidLoad.

 override func viewDidLoad() {
        super.viewDidLoad()

        navigationItem.title = "Scrollable rows"
        configureHierarchy()
  }

Нам остался последний шаг. Создать и сконфигурировать DataSource.

func configureDataSource() {

// Создадим массив эмоджи, которые мы будем отображать в ячейках нашей таблицы

        let emojies = ["						
Источник: https://habr.com/ru/articles/741266/


Интересные статьи

Интересные статьи

Raspberry Pi — почти что идеальный вариант одноплатника как для корпоративный проектов, так и для собственных DIY-проектов. Эти системы относительно недорогие, функциональные и небольшие по размеру,...
Привет, Хабр! Мы — команда RapidSoft и сегодня хотим рассказать, как мы разработали и внедрили нестандартное решение системы лояльности клиентов SBI банка, как удалось в кратчайшие сроки успеть вы...
Прошло 4 месяца с написания предыдущей статьи, за это время произошло довольно много нового как по технической части, так и по позиционированию девайса. В статье я расск...
У каждой инновационной компании рано или поздно возникает вопрос по выбору юридической фирмы для защиты своих прав на изобретения. В Parallels эта тема возникла в момент объединения портфелей...
Продолжаем голосовать за интересные доклады в секции «Хранилища данных (Storage)» на DevConfX, которая пройдет уже через неделю. Обратите внимание на доклад о сертификации специалистов PostgreSQL...