UICollection Compositional Layout Part 2

In previous part we covered the basic of compositional layout . In this part we will see more advanced topic.

Compositional Layout with Custom Model

As shown in Figure 1 we created collection view cell called topApp in App Store

Figure 1

Since out item model is change we want TopAppModel to be used as Item data source, in order to diffable data source to work it should conform to Hashable

Figure 2

As shown in Figure 3 and Figure 4, we now used custom View Model for cell rendering and we just make it conform to Hashable

Figure 3
Figure 4

Hashable

As you can see in Figure 5

  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

Here I created identifier property to uniquely identify object since in our model there is no unique field , if some unique value is coming from server you can use that one

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

This is the data source and you are thinking what if we need section 2 to use different model we will look this in later part, Now section 1 and section 2 both uses same model to populate it’s item which different layout

Figure 9

Section 2 cell code if you want to look

Figure 10

Nested Layout Group

The core layout thing inside compositional layout is layout group annd layout group is actually a subtype of NSCollectionLayoutItem, Now , because this is a relationship, when you specify the items that are in a layout group, you can also have other groups. So you can nest these. And there’s no limit to this particular nesting, it’s arbitrary. And because we have this, it unlocks a ton of interesting new designs.

In this example group is comprises of three items on the leading side it has one monster item and it has vertical group contains two items on the trailing side . From code side we have this horizontal group and it has subitems the leading monster item itself and a trailing group . As shown in Figure 10 we did few things

  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

As shown in Figure 12 we created layout where item will take whole screen width and height is constant or absolute and one important thing is orthogonalScrollingBehavior = .continuous

orthogonalScrollingBehavior : The section’s scrolling behavior in relation to the main layout axis.

Figure 12

As you can see in Gif 1 , it work like it will line one up item horizontally and never go to new line

Gif 1

As you can see in Figure 13 ,we comment out orthogonalScrollingBehavior so it used default which is none →The section does not allow users to scroll its content orthogonally. so it add item vertically

Figure 13

As shown in gif 2 we used paging as orthogonalScrollingBehavior and it will do item to item scrolling if you previously work on old school collections view you know this
section.orthogonalScrollingBehavior = .paging

Gif 2

As shown in Figure 14 we created nested group with three items and I created white rectangle to specify each group so by using .groupPaging when you scroll you will see another group so in short always scrolling stop when. group starts

Figure 14
Gif 3

by using .groupPagingCentered when you scroll it will do the group pagination annd place group at the center of screen

continuousGroupLeadingBoundary → The section allows users to scroll its content orthogonally, coming to a natural stop at the leading boundary of the visible group.

continuous → The section allows users to scroll its content orthogonally with continuous scrolling

none → The section does not allow users to scroll its content orthogonally.

paging → The section allows users to page its content orthogonally.

groupPaging → The section allows users to page its content orthogonally one group at a time.

groupPagingCentered → The section allows users to page its content orthogonally one group at a time, centering each group.

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

https://developer.apple.com/videos/play/wwdc2019/215

Senior iOS Engineer | HungerStation | Delivery Hero