Detailed look at the NSCollectionLayoutGroup
With the NSCollectionLayoutGroup definition we can create quite different layouts while keeping the rest of the code the same.
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:
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
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:
Not very exciting, I know. Notice the large gaps between the items, that is our
This layout is produced mainly by this line of code:
let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitem: item, count: 1)
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:
We could also achieve this by changing the size of the
NSCollectionLayoutItem but in this post we are concerned with the layout groups.
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
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:
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