'UICollectionViewCompositionalLayout, but not a repeating pattern
As you can see this layout has a pattern of cells 0, 1, 2, 0, 1, 2, 0, 1, 2 with respect to the size. I want my layout to depict 0, 1, 2, 1, 2, 1, 2, 1, 2 as the pattern with respect to size. In other words, just have the first cell to be of large size and the others should take up a size to fit the row of 2. My current code for the layout:
import UIKit
struct Layout {
private struct LayoutConstants {
static let largeGroupHeight: CGFloat = 406
static let leadingInset: CGFloat = 8
static let topInset: CGFloat = 10
static let bottomInset: CGFloat = 15
static let itemCount = 2
static let fractionalConstant: CGFloat = 1.0
static let fractionalWidthLeading: CGFloat = 0.67
static let fractionalWidthTrailing: CGFloat = 1.0
static let fractionalHeightTrailing: CGFloat = 0.3
static let fractionalContainerWidth: CGFloat = 1.2
static let groupFractionalHeight: CGFloat = 0.33
}
func layoutSection() -> NSCollectionLayoutSection {
let leadingItem = NSCollectionLayoutItem(
layoutSize: NSCollectionLayoutSize(
widthDimension: .fractionalWidth(LayoutConstants.fractionalWidthLeading),
heightDimension: .fractionalHeight(LayoutConstants.fractionalConstant)))
leadingItem.contentInsets = NSDirectionalEdgeInsets(top: LayoutConstants.topInset,
leading: LayoutConstants.topInset,
bottom: LayoutConstants.bottomInset,
trailing: LayoutConstants.leadingInset)
let trailingItem = NSCollectionLayoutItem(
layoutSize: NSCollectionLayoutSize(
widthDimension: .fractionalWidth(LayoutConstants.fractionalWidthTrailing),
heightDimension: .fractionalHeight(LayoutConstants.fractionalHeightTrailing)))
trailingItem.contentInsets = NSDirectionalEdgeInsets(top: LayoutConstants.topInset,
leading: LayoutConstants.leadingInset,
bottom: LayoutConstants.bottomInset,
trailing: LayoutConstants.leadingInset)
let trailingGroup = NSCollectionLayoutGroup.vertical(
layoutSize: NSCollectionLayoutSize(
widthDimension: .fractionalWidth(LayoutConstants.groupFractionalHeight),
heightDimension: .fractionalHeight(LayoutConstants.fractionalConstant)),
subitem: trailingItem,
count: LayoutConstants.itemCount)
var subitems: [NSCollectionLayoutItem] = []
subitems.append(leadingItem)
subitems.append(trailingGroup)
let containerGroup = NSCollectionLayoutGroup.horizontal(
layoutSize: NSCollectionLayoutSize(
widthDimension: .fractionalWidth(LayoutConstants.fractionalContainerWidth),
heightDimension: .absolute(LayoutConstants.largeGroupHeight)),
subitems: subitems)
let section = NSCollectionLayoutSection(group: containerGroup)
section.orthogonalScrollingBehavior = .continuous
return section
}
}
Solution 1:[1]
I found different approach to do it as following:
- I will use two sections.
Section1 for the first number, it will hold a group of one item.
Section2 for everything else, it will hold a group of two items (stacked vertically). - We need to change the scroll direction of collection view to horizontal.
Normally all sections are stacked vertically, so the two sections will be stacked vertically and won't give us what we want. - We need to change the layout configurations for groups and items so it can work correctly for the horizontal scroll direction.
That's it, now for the code.
ADVICE: Please try to gradually move from your solution to mine to learn the different issues I learned while testing, it will help you understand why for each piece.
NOTE: I used values instead of your constants so it doesn't confuse you, because now constants need to be changed/renamed to fit this approach.
- Section1 (One group of one item)
func createSection1() -> NSCollectionLayoutSection {
let item = NSCollectionLayoutItem(
layoutSize: NSCollectionLayoutSize(
widthDimension: .fractionalWidth(1.0),
heightDimension: .fractionalHeight(1.0)
)
)
item.contentInsets = NSDirectionalEdgeInsets(
top: 10,
leading: 10,
bottom: 15,
trailing: 8
)
let group = NSCollectionLayoutGroup.horizontal(
layoutSize: NSCollectionLayoutSize(
widthDimension: .fractionalWidth(0.67),
heightDimension: .absolute(406)
),
subitem: item,
count: 1
)
return NSCollectionLayoutSection(group: group)
}
- Section2 (One group of two items stacked vertically)
func createSection2() -> NSCollectionLayoutSection {
let item = NSCollectionLayoutItem(
layoutSize: NSCollectionLayoutSize(
widthDimension: .fractionalWidth(1.0),
heightDimension: .fractionalHeight(0.3)
)
)
item.contentInsets = NSDirectionalEdgeInsets(
top: 10,
leading: 8,
bottom: 15,
trailing: 8
)
let group = NSCollectionLayoutGroup.vertical(
layoutSize: NSCollectionLayoutSize(
widthDimension: .fractionalWidth(0.33),
heightDimension: .absolute(406)
),
subitem: item,
count: 2
)
let section = NSCollectionLayoutSection(group: group)
return section
}
- The final layout
Please notice the line indicating scrollDirection change
func createLayout() -> UICollectionViewLayout {
let layout = UICollectionViewCompositionalLayout {
[weak self] (sectionIndex: Int, layoutEnvironment: NSCollectionLayoutEnvironment) -> NSCollectionLayoutSection? in
guard let self = self else { return nil }
if sectionIndex == 0 {
return self.createSection1()
} else {
return self.createSection2()
}
}
// Changing scrollDirection
let config = UICollectionViewCompositionalLayoutConfiguration()
config.scrollDirection = .horizontal
layout.configuration = config
return layout
}
- Finally, here as suggession of how to handle it in datasource
func numberOfSections(in collectionView: UICollectionView) -> Int {
2
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
data.isEmpty
? 0
: section == 0 ? 1 : data.count - 1
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(
withReuseIdentifier: String(describing: Cell.self),
for: indexPath
) as! Cell
if indexPath.section == 0 {
cell.number = data[0]
cell.color = colors[0]
} else {
cell.number = data[indexPath.row + 1]
cell.color = colors[indexPath.row + 1]
}
return cell
}
- Demo
That's it, please let me know if you have any question.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Ahmed Shendy |

