Here's the code:
func layout() -> UICollectionViewLayout {
UICollectionViewCompositionalLayout(sectionProvider: { [self] row, _ in
var cellItems: [NSCollectionLayoutItem] = []
let rowHeight = NSCollectionLayoutDimension.absolute(44)
var rowWidth: CGFloat = 0.0
for column in 0..<10 {
let cellWidth = NSCollectionLayoutDimension.absolute(100)
let cellSize = NSCollectionLayoutSize(widthDimension: cellWidth, heightDimension: rowHeight)
let cell = NSCollectionLayoutItem(layoutSize: cellSize)
cellItems.append(cell)
rowWidth += width
}
var rowBoundaryItems: [NSCollectionLayoutBoundarySupplementaryItem] = []
var groupOffset: CGFloat = 0.0
if let rowHeader = header(for: row) {
groupOffset = 60
rowBoundaryItems.append(rowHeader)
}
rowWidth += groupOffset
let rowSize = NSCollectionLayoutSize(widthDimension: .absolute(rowWidth), heightDimension: rowHeight)
let group = NSCollectionLayoutGroup.horizontal(layoutSize: rowSize, subitems: cellItems)
group.contentInsets = NSDirectionalEdgeInsets(top: 0, leading: groupOffset, bottom: 0, trailing: 0)
let section = NSCollectionLayoutSection(group: group)
section.boundarySupplementaryItems = rowBoundaryItems
return section
}, configuration: configuration)
}
var configuration: UICollectionViewCompositionalLayoutConfiguration {
let configuration = UICollectionViewCompositionalLayoutConfiguration()
var boundaryItems: [NSCollectionLayoutBoundarySupplementaryItem] = []
if let topLeftItem = topLeftView {
boundaryItems.append(topLeftItem)
}
boundaryItems += columnHeaderItems
configuration.boundarySupplementaryItems = boundaryItems
return configuration
}
var topLeftView: NSCollectionLayoutBoundarySupplementaryItem? {
let columnHeaderHeight = NSCollectionLayoutDimension.absolute(44)
let topLeftCellSize = NSCollectionLayoutSize(widthDimension: NSCollectionLayoutDimension.absolute(60, heightDimension: columnHeaderHeight)
let topLeftCell = NSCollectionLayoutBoundarySupplementaryItem(
layoutSize: topLeftCellSize,
elementKind: "topLeftHeader",
alignment: .topLeading
)
topLeftCell.pinToVisibleBounds = true
topLeftCell.zIndex = 3
return topLeftCell
}
var columnHeaderItems: [NSCollectionLayoutBoundarySupplementaryItem] {
var headerItems: [NSCollectionLayoutBoundarySupplementaryItem] = []
var offset = 60
for column in 0..<datasource.numberOfColumns {
let width = dimensionsProvider.widthForColumn(column)
let columnHeaderSize = NSCollectionLayoutSize(widthDimension: .absolute(100), heightDimension: .absolute(44))
let headerView = NSCollectionLayoutBoundarySupplementaryItem(
layoutSize: columnHeaderSize,
elementKind: "columnHeader",
alignment: .topLeading,
absoluteOffset: CGPoint(x: offset, y: 0)
)
headerView.pinToVisibleBounds = true
headerView.zIndex = 2
offset += width
headerItems.append(headerView)
}
return headerItems
}
func header(for row: Int) -> NSCollectionLayoutBoundarySupplementaryItem? {
let rowHeight = 44
let headerSize = NSCollectionLayoutSize(widthDimension: .absolute(60, heightDimension: .absolute(rowHeight))
let header = NSCollectionLayoutBoundarySupplementaryItem(layoutSize: headerSize, elementKind: "rowHeader", alignment: .leading)
header.pinToVisibleBounds = true
header.zIndex = 1
return header
}