UICollection Compositional Layout Part 2

Compositional Layout with Custom Model

Figure 1
Figure 2
Figure 3
Figure 4

Hashable

  1. For 1 section example we only conform to Hashable which means all value in object should be same to generate same hash value and same for == operator
  2. For 2 section example we conform to Hashable and say has should be generate with serialNumber which means if onlyserialNumber value in object should be same to generate same hash value and for == operator still whole object value will same
  3. For last section if serialNumber in objects is same it will produce same hash and both object are equal as well
Figure 5
Figure 6

Different Layout Per Section

  1. Previously we were using one layout for all section UICollectionViewCompositionalLayout(section: section) now we will create two sections with two different layout x
  2. Previously when you created the collection view layout , you started of by defining the item size and so on. This approach allow to define a layout that is applied to all the sections in the collection view
  3. When using the UICollectionDataSource protocol you could use indexpath to customize cell size or section behaviour based on which section you were in, we can so the same in here as well when define a layout
  4. As shown in Figure 7 here we define a constant section provider that takes closure , the argument pass into this closure are the section index , along with the layout environment (the object contains information about the layout environment at the time collection view is setup , properties like trait collection and information about the layout container what is the content size and so on) you can customize section layout based on this runtime information as well
  5. The closure return the instance of NSCollectionLayoutSection class which is what you need to build up to
  6. You use a section provider to create a compositional layout (UICollectionViewCompositionalLayout) that has multiple sections with different layouts. The section provider keeps track of the index of the section that it’s currently creating, so you can configure each section differently. typealias UICollectionViewCompositionalLayoutSectionProvider = (Int, NSCollectionLayoutEnvironment) -> NSCollectionLayoutSection?
  7. Since we have different layout for each section we created UICollectionViewCompositionalLayout instance with section provider constructor , Note section provider is escaping closure so be check for memory leak stuff
  8. For section 1 we used the same layout
  9. For section 2 we used two column based layout and only show image, one addition thing group.interItemSpacing = .fixed(10) it will add 10 points between items in group
  10. interItemSpacing take NSCollectionLayoutSpacing → An object that defines the space between or around items in a collection view. In a collection view layout, you use a spacing object to specify both the amount of space and the way in which it’s calculated. You can express spacing using fixed or flexible spacing. Use fixed spacing to provide an exact amount of space. For example, the following code creates exactly 10 points of space between the items in the group. Use flexible spacing to provide a minimum amount of space that can grow as more space becomes available. For example, the following code creates at least 10 points of space between the items in the group. As more space becomes available, items are re spaced evenly in the additional space.
Figure 7
Figure 8
Figure 9
Figure 10

Nested Layout Group

  1. First we create a leading monster item which will take 70% of its parent and it will take 100% of parent height
  2. The we create layout data for trailingItem which will take 100% of its parent width and 30% of its parent height
  3. Third we created trailing group with vertical direction and add two items that we created in step 2
  4. trailing group will take 30% of parent width and will take 100% of parent height
  5. Finally we created nestedGroup horizontal and add leading and trailing group.
  6. nestedGroup will take 100% width of its parent which is section and section width ultimately the width of main layout which is whole screen width
  7. nestedGroup will take 100% height of its parent which is section and section width ultimately take height of main layout which is whole screen height
  8. Note trailing group have two items and for child it act as parent so each child will take 100% parent width and trailing group have 0.3 width of screen.
  9. So by looking into this example you can imagine what you can do with compositional layout.
Figure 11

Nested Collection View

Figure 12
Gif 1
Figure 13
Gif 2
Figure 14
Gif 3

DataSource code

private func configureDataSource() {dataSource = UICollectionViewDiffableDataSource<Section, TopAppModel>(collectionView: collectionView) { (collectionView, indexPath, topAppModel) -> UICollectionViewCell? inif indexPath.section == 0 {guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: TopApp.reuseIdentifier, for: indexPath) as? TopApp else {fatalError("Cannot create new cell")}cell.appImageView.image =  UIImage(named: topAppModel.imageNamed)cell.title.text = topAppModel.titlecell.subtitle.text = topAppModel.subTitlecell.backgroundColor = .redreturn cell} else if indexPath.section == 1 {guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: FeatureCell.reuseIdentifier, for: indexPath) as? FeatureCell else {fatalError("Cannot create new cell")}cell.image.image =  UIImage(named: topAppModel.imageNamed)cell.backgroundColor = .redreturn cell} else if indexPath.section == 2 {guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: NumberCell.reuseIdentifier, for: indexPath) as? NumberCell else {fatalError("Cannot create new cell")}cell.numberLabel.text = topAppModel.titlecell.backgroundColor = .redreturn cell} else {guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: FeatureCell.reuseIdentifier, for: indexPath) as? FeatureCell else {fatalError("Cannot create new cell")}cell.image.image =  UIImage(named: topAppModel.imageNamed)cell.backgroundColor = .redreturn cell}}// initial datavar snapshot = NSDiffableDataSourceSnapshot<Section, TopAppModel>()snapshot.appendSections([.topApp, .grid, .nestedGroup, .nestedCollection])snapshot.appendItems(TopAppModel.mock, toSection: .topApp)snapshot.appendItems(TopAppModel.mock, toSection: .grid)snapshot.appendItems(TopAppModel.mock, toSection: .nestedGroup)snapshot.appendItems(TopAppModel.mockFoodApp, toSection: .nestedCollection)dataSource.apply(snapshot, animatingDifferences: false)}

Useful Links

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Ali Akhtar

Ali Akhtar

Senior iOS Engineer | HungerStation | Delivery Hero