← Назад к вопросам

Что такое Compositional Layout?

1.8 Middle🔥 191 комментариев
#UIKit и верстка

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI5 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Что такое Compositional Layout?

Compositional Layout — это современный, декларативный и гибкий API, представленный Apple в iOS 13 (в рамках фреймворка UIKit) для построения сложных и адаптивных макетов в коллекциях (UICollectionView). Он пришёл на смену старому, более императивному и монолитному UICollectionViewFlowLayout, предлагая модульный подход к компоновке интерфейса. Основная философия заключается в "композиции" (отсюда и название) — сборке сложного макета из небольших, независимых и многократно используемых компонентов.

Ключевые компоненты Compositional Layout

Структура строится на трёх основных "кирпичиках", которые вкладываются друг в друга по иерархии:

  1. NSCollectionLayoutItem (Элемент) — это фундаментальная единица, представляющая самую маленькую отрисовываемую часть, обычно ячейку (cell). Элемент определяет свой размер.

    let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),
                                          heightDimension: .fractionalHeight(1.0))
    let item = NSCollectionLayoutItem(layoutSize: itemSize)
    
  2. NSCollectionLayoutGroup (Группа) — контейнер, который объединяет один или несколько NSCollectionLayoutItem (или даже другие группы) и определяет, как они располагаются относительно друг друга — горизонтально, вертикально или в пользовательской конфигурации. Группа управляет внутренним расположением элементов.

    // Горизонтальная группа из 3 элементов
    let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),
                                           heightDimension: .absolute(44))
    let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize,
                                                   subitem: item,
                                                   count: 3)
    
  3. NSCollectionLayoutSection (Секция) — контейнер верхнего уровня, который объединяет одну или несколько NSCollectionLayoutGroup. Секция определяет поведение всего блока интерфейса: интервалы (interGroupSpacing), заголовки и футеры, отступы (contentInsets), а также возможность прикрепления заголовка (orthogonalScrollingBehavior).

    let section = NSCollectionLayoutSection(group: group)
    section.interGroupSpacing =間隔10
    section.orthogonalScrollingBehavior = .continuous // Для горизонтального скролла внутри секции
    

Итоговый макет создаётся композицией этих частей в объект UICollectionViewCompositionalLayout.

let layout = UICollectionViewCompositionalLayout { sectionIndex, layoutEnvironment in
    // Здесь, на основе номера секции или окружения, можно возвращать разные макеты
    return createCustomSection(for: sectionIndex)
}
collectionView.setCollectionViewLayout(layout, animated: false)

Преимущества перед UICollectionViewFlowLayout

  • Модульность и переиспользование: Вы можете создать библиотеку независимых компонентов-макетов (секций) и комбинировать их как "Лего".
  • Ортогональная прокрутка (Orthogonal Scrolling): Реализация горизонтально скроллящих секций внутри вертикальной коллекции становится тривиальной задачей (см. свойство .orthogonalScrollingBehavior выше). Это главная "фишка" для создания интерфейсов, подобных App Store.
  • Декларативность: Код для описания макета более читаем и сосредоточен на что должно быть, а не на как это вычислять.
  • Адаптивность (Adaptive Layouts): Используя NSCollectionLayoutEnvironment, можно легко создавать разные макеты для различных размеров класса (compact, regular), учитывая ориентацию устройства или размер контейнера (например, iPad vs iPhone, split-view).
  • Поддержка заголовков/футеров на уровне секций и глобальных (Boundary Supplementary Items): Более мощная и гибкая система, чем раньше.
  • Вложенность групп (Nested Groups): Позволяет создавать невероятно сложные сетки и иерархические структуры.

Практический пример: Сетка с ортогональным скроллом

Типичный сценарий — главный экран приложения с вертикальным скроллом, где одна секция — это сетка 3x2, а следующая — горизонтально скроллящийся ряд.

func createLayout() -> UICollectionViewLayout {
    return UICollectionViewCompositionalLayout { (sectionIndex: Int, layoutEnvironment: NSCollectionLayoutEnvironment) -> NSCollectionLayoutSection? in
        
        switch sectionIndex {
        case 0:
            // Секция 0: Сетка 3x2
            let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1/3),
                                                  heightDimension: .fractionalHeight(1.0))
            let item = NSCollectionLayoutItem(layoutSize: itemSize)
            item.contentInsets = NSDirectionalEdgeInsets(top: 2, leading: 2, bottom: 2, trailing: 2)
            
            let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),
                                                   heightDimension: .fractionalWidth(1/3 * 0.75)) // Сохраняем пропорции
            let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item])
            
            let section = NSCollectionLayoutSection(group: group)
            return section
            
        case 1:
            // Секция 1: Горизонтальный скроллинг
            let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),
                                                  heightDimension: .fractionalHeight(1.0))
            let item = NSCollectionLayoutItem(layoutSize: itemSize)
            
            let groupSize = NSCollectionLayoutSize(widthDimension: .absolute(160),
                                                   heightDimension: .absolute(220))
            let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item])
            
            let section = NSCollectionLayoutSection(group: group)
            section.orthogonalScrollingBehavior = .continuous // Включаем горизонтальный скролл!
            section.interGroupSpacing = 10
            section.contentInsets = NSDirectionalEdgeInsets(top: 10, leading: 16, bottom: — отступ30, trailing: 16)
            return section
            
        default:
            return nil
        }
    }
}

Итог: Compositional Layout — это мощный инструмент, который кардинально упростил создание современных, сложных и отзывчивых интерфейсов в iOS. Его изучение и внедрение является практически обязательным для любого iOS-разработчика, работающего с коллекциями, так как он стал стандартом де-факто в экосистеме UIKit.