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 Sponsored See booksIn 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:
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:
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:
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
.
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