iOS now provides a newer more flexible, composable way to construct collection views. UICollectionViewCompositionalLayout
was introduced in iOS 13 at WWDC 2019. Prior to UICollectionViewCompositionalLayout
we used UICollectionViewFlowLayout
.
This repositiory has 5 projects:
- Introduction
- Multiple Sections
- Nested Groups and Orthogonal Scrolling
- Photo Search - Compositional Layout and Combine
- Adaptive Layout
- Composable
- Flexible
- Fast
- Understand the building blocks needed in creating a compositional layout.
- Use
UICollectionViewDiffableDataSource
to configure your collection view. - Build a grid view with multiple columns.
- Understand and use supplementary views.
- Understand and use
UICollectionViewCompositionalLayout
provider to return various section configurations. - Understand and use orthorgonal scrolling.
- NSCollectionLayoutSize
- NSCollectionLayoutItem
- NSCollectionLayoutGroup
- NSCollectionLayoutSection
Item -> Group -> Section -> Layout
Above a layout is made up of sections, a section has groups and inside groups we have items.
The size is of type NSCollectionLayoutDimension
- .fractionalWidth
- .fractionalHeight
- .absolute (point based values e.g 200 points)
- .estimated (will start with an estimation and grow accordingly)
There are three ways to layout
- Horizontal
- Vertical
- Custom
@IBOutlet weak var collectionView: UICollectionView!
A compositional layout is made of an item -> group -> section -> layout. An item is the smallest component. An item belongs to a group. A group belongs to a section. A layout is made of one or more sections.
private func createLayout() -> UICollectionViewLayout {
// 1
// setup the item
let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(0.25), heightDimension: .fractionalHeight(1.0))
let item = NSCollectionLayoutItem(layoutSize: itemSize)
item.contentInsets = NSDirectionalEdgeInsets(top: 2, leading: 2, bottom: 2, trailing: 2)
// 2
// setup the group
let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .fractionalWidth(0.25))
let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item])
// 3
// setup the section
let section = NSCollectionLayoutSection(group: group)
// 4
// setup the layout
let layout = UICollectionViewCompositionalLayout(section: section)
return layout
}
Using Storyboard
collectionView.collectionViewLayout = createLayout()
collectionView.backgroundColor = .systemBackground
Programmatically
collectionView = UICollectionView(frame: view.bounds, collectionViewLayout: createLayout())
private var dataSource: UICollectionViewDiffableDataSource<Section, Int>!
enum Section {
case main
}
private func configureDataSource() {
// 1
dataSource = UICollectionViewDiffableDataSource<Section, Int>(collectionView: collectionView, cellProvider: { (collectionView, indexPath, value) -> UICollectionViewCell? in
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "labelCell", for: indexPath) as? LabelCell else {
fatalError()
}
cell.textLabel.text = "\(value)"
cell.backgroundColor = .systemOrange
return cell
})
// 2
var snapshot = NSDiffableDataSourceSnapshot<Section, Int>()
snapshot.appendSections([.main])
snapshot.appendItems(Array(1...100), toSection: .main)
dataSource.apply(snapshot, animatingDifferences: false)
}
configureCollectionView()
configureDataSource()