I am converting some hairy collection view code (scroll views with embedded stack views, collection views, table views, etc.) to a single collection view with compositional layout. But I am having troubles with “two column” layout when using the count
parameter.
To experiment, I downloaded Apple’s Implementing Modern Collection Views sample, looked at the Create a Column Layout code, which has this example:
extension TwoColumnViewController {
/// - Tag: TwoColumn
func createLayout() -> UICollectionViewLayout {
let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),
heightDimension: .fractionalHeight(1.0))
let item = NSCollectionLayoutItem(layoutSize: itemSize)
let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),
heightDimension: .absolute(44))
let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitem: item, count: 2)
let spacing = CGFloat(10)
group.interItemSpacing = .fixed(spacing)
let section = NSCollectionLayoutSection(group: group)
section.interGroupSpacing = spacing
section.contentInsets = NSDirectionalEdgeInsets(top: 0, leading: 10, bottom: 0, trailing: 10)
let layout = UICollectionViewCompositionalLayout(section: section)
return layout
}
}
In their demo app, you get there by navigating to “Compositional Layout” » “Getting Started” » “Two-Column Grid”. Anyway, this yields:
OK, that’s fine.
But in iOS 16, horizontal(layoutSize:subitem:count:)
is deprecated:
And if you replace it with horizontal(layoutSize:repeatingSubitem:count:)
, you get a layout like the following (where you cannot even scroll to the right to see the cells offscreen):
How do you get columnar output in iOS 16 and later?
Unlike horizontal(layoutSize:subitem:count:)
, with horizontal(layoutSize:repeatingSubitem:count:)
you have to adjust the width of the item or group. E.g.:
extension TwoColumnViewController {
/// - Tag: TwoColumn
func createLayout() -> UICollectionViewLayout {
let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(0.5), // NB: 0.5, not 1.0
heightDimension: .fractionalHeight(1))
let item = NSCollectionLayoutItem(layoutSize: itemSize)
let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1),
heightDimension: .absolute(44))
let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, repeatingSubitem: item, count: 2)
let spacing = CGFloat(10)
group.interItemSpacing = .fixed(spacing)
let section = NSCollectionLayoutSection(group: group)
section.interGroupSpacing = spacing
section.contentInsets = NSDirectionalEdgeInsets(top: 0, leading: 10, bottom: 0, trailing: 10)
let layout = UICollectionViewCompositionalLayout(section: section)
return layout
}
}
As the documentation for the new method says:
It’s your responsibility to ensure that the group’s
layoutSize
can fitcount
repetitions of this item.
I find that I can either adjust the widthDimension
of the NSCollectionLayoutItem
of the item or the group to .fractionalWidth(0.5)
, and it renders the two-column collection view.
I hope the above helps someone else save a little time when working through Apple’s compositional layout examples.