Detailed look at the NSCollectionLayoutGroup

With the NSCollectionLayoutGroup definition we can create quite different layouts while keeping the rest of the code the same.

Published: Jan. 3, 2021

In this post I would like introduce NSCollectionLayoutGroup class which is part of the Compositional Layout for Collection View. This assumes you know the basic classes and how they relate to each other. You can read my previous post, which details the basic anatomy of compositional layout. In that post I outlined what we can do with NSCollectionLayoutGroup and also hinted at its complexity.

These are the layouts we are going to create:

CL-groups-example

Preparation

We will use super simple layout to start with, below is the entire code:

let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .fractionalHeight(1.0))

let item = NSCollectionLayoutItem(layoutSize: itemSize)
item.contentInsets = NSDirectionalEdgeInsets(top: 5, leading: 5, bottom: 5, trailing: 5)

// we will be working with this part
let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .fractionalWidth(0.5))
let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitem: item, count: 1)

let section = NSCollectionLayoutSection(group: group)
section.interGroupSpacing = 30

let layout = UICollectionViewCompositionalLayout(section: section)
return layout

This is the needed "boilerplate" code. This layout is then assigned to the CollectionView like this:

collectionView.setCollectionViewLayout(layout, animated: false)

As you can see, our layout has just a single section to keep things simple. I have also set the section.interGroupSpacing to a high value so we can see the individual groups.

In this post, we won't touch the NSCollectionLayoutItem or NSCollectionLayoutSection. We will work with just the NSCollectionLayoutGroup to see how we can create interesting layouts with just changing the group definition.

If we run the app (I am using my example project available on GitHub), we will get this list of sorts:

CL-basic-group-example

Not very exciting, I know. Notice the large gaps between the items, that is our section.interGroupSpacing.

This layout is produced mainly by this line of code:

let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitem: item, count: 1)

Basic grid

We are saying we want a horizontal group with one item. In this case we could use vertical and the result would be roughly the same. Depending on the content insets and similar stuff. Let's make a tiny change and change the count to 2:

let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitem: item, count: 2)

And now we get a basic grid:

CL-basic-grid-example

We could also achieve this by changing the size of the NSCollectionLayoutItem but in this post we are concerned with the layout groups.

Vertical layout

If we moved the count to 3, then we would have three items side by side inside each group. Let's say we want three items vertically.

let group = NSCollectionLayoutGroup.vertical(layoutSize: groupSize, subitem: item, count: 3)

We switched to vertical variant and modified the count.

CL-vertical-example

We could achieve this by simply having one item in a group. However this layout is useful if we wanted to have horizontal scrolling. The section would then have groups of three that the user can scroll horizontally.

So far we have seen how modifying just the NSCollectionLayoutGroup definitions gives us flexibility when creating our layout.

Using subgroup for more complex layout

Now let's see a more complex example. One of the "superpower" of groups is that the sub-item can also be a group. This is needed when we want multiple items both vertically and horizontally.

Let's define this vertical subgroup:

let subgroup = NSCollectionLayoutGroup.vertical(layoutSize: NSCollectionLayoutSize(widthDimension: .fractionalWidth(0.5), heightDimension: .fractionalWidth(0.5)), subitem: item, count: 2) 

Which we can use as the subitem parameter with count:

let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitem: subgroup, count: 2)

And the result:

CL-subgroup-example

This is another layout primarily useful for horizontal scrolling. If we wanted to have one large item along with a few smaller ones, we would also need to work with the definition of NSCollectionLayoutItem which is outside the scope for this article.

Uses: Xcode 12 & Swift 5.3

Filip Němeček profile photo

WRITTEN BY

Filip Němeček @nemecek_f

iOS blogger and developer with interest in Python/Django. My recent projects include IndieAppsCatalog and ImpressKit.

iOS blogger and developer with interest in Python/Django. My recent projects include IndieAppsCatalog and ImpressKit.