Reputation: 330
I am using the UICollectionViewCompositionalLayout to layout my cells in a collectionView. I want the width of the items in a row to auto adjust so as to fill the collectionView's width. However this is not happening even after setting the fractionalWidth to 1.0 on groupSize. Here is the code:
override func viewDidLoad() {
super.viewDidLoad()
collectionView = UICollectionView(frame: .zero, collectionViewLayout: createCollectionViewLayout())
collectionView.backgroundColor = UIColor(red: 157.0/255.0, green: 159.0/255.0, blue: 162.0/255.0, alpha: 0.5)
collectionView.register(CollectionViewCell.self, forCellWithReuseIdentifier: "Cell")
collectionView.dataSource = dataSource
}
private func createCollectionViewLayout() -> UICollectionViewLayout {
// Define Item Size
let itemSize = NSCollectionLayoutSize(widthDimension: .estimated(100.0), heightDimension: .absolute(52.0))
// Create Item
let item = NSCollectionLayoutItem(layoutSize: itemSize)
// Define Group Size
let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .absolute(52.0))
// Create Group
let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [ item ])
group.interItemSpacing = .fixed(1.0)
// Create Section
let section = NSCollectionLayoutSection(group: group)
return UICollectionViewCompositionalLayout(section: section)
}
Upvotes: 3
Views: 1371
Reputation: 77672
You're running into a couple problems.
A UICollectionView
is designed to take the cell widths you have declared - explicitly or with or auto-layout determined sizes - and arranges them to "wrap" or scroll.
You're trying to get the collection view to set the sizes for you.
The most straightforward way to get the layout you want is for you (the designer/developer) to decide how wide you want your cells as percentages of the width.
So, you may want:
20% | 40% | 20% | 20%
but you also want 1-point inter-item spacing.
Because collection views won't layout cells on "partial pixels," you need to allow for approximately 1-point inter-item spacing.
To get that, make sure you percentages add up to less-than 100%:
20% | 39% | 20% | 20%
and use:
group.interItemSpacing = .flexible(1.0)
Here's a modified version of your createCollectionViewLayout()
func:
private func createCollectionViewLayout() -> UICollectionViewLayout {
// array of cell widths as Percentages
// total must be less than 1.0 to leave space
// for inter-item spacing
let percentageWidths: [CGFloat] = [
0.20, 0.39, 0.20, 0.20, // total == 0.99
]
// array of NSCollectionLayoutItem
var items: [NSCollectionLayoutItem] = []
percentageWidths.forEach { w in
let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(w), heightDimension: .absolute(52.0))
let item = NSCollectionLayoutItem(layoutSize: itemSize)
items.append(item)
}
// Define Group Size
let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .absolute(52.0))
// Create Group with items array
let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: items)
// use .flexible(1.0) for .interItemSpacing
// so we get *about* 1.0-points between cells
group.interItemSpacing = .flexible(1.0)
// Create Section
let section = NSCollectionLayoutSection(group: group)
return UICollectionViewCompositionalLayout(section: section)
}
Since you said: "proportional" seems to be the thing I am looking for ... that might be sufficient for you.
If you really want exactly 1-point-wide inter-item spacing, you'll have some more work to do... you'll need to calculate your actual cell widths and convert them to percentages of the total, allowing for an extra 3-points for the spacing, and then round the values so they don't fall on partial-pixels.
Upvotes: 2