DrCi
DrCi

Reputation: 1

UICollectionView UICollectionViewCompositionalLayout with horizontal scrollDirection has overlapping header/footer/content

I am trying to setup a UICollectionView with multiple pages of the same height placed horizontally, only one page visible at a time, each page having a header + rows of buttons + footer.

    let layout = UICollectionViewCompositionalLayout { [weak self] sectionIndex, environment in
        self?.createSectionLayout(for: sectionIndex, in: environment)
    }
    let configuration = UICollectionViewCompositionalLayoutConfiguration()
    configuration.scrollDirection = .horizontal
    layout.configuration = configuration
    
    collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
    collectionView.allowsMultipleSelection = true
    collectionView.delegate = self
    collectionView.dataSource = self
    collectionView.isPagingEnabled = true
    collectionView.showsHorizontalScrollIndicator = false
    collectionView.bounces = true
    collectionView.register(MyViewCell.self, forCellWithReuseIdentifier: Constants.reuseIdentifier)
    contentView.addSubview(collectionView)
    collectionView.translatesAutoresizingMaskIntoConstraints = false

and the implementation of the layout:

func createSectionLayout(for sectionIndex: Int, in environment: NSCollectionLayoutEnvironment) -> NSCollectionLayoutSection {
    let template = templateCollection.templates[sectionIndex]
    let insets = template.hasFooter
        ? Constants.layoutDirectionalContentInsets
        : Constants.layoutDirectionalContentInsetsShortBottom
    let numberOfItems = template.items.count
    let columnCount = 4
    let contentSize = environment.container.contentSize
    let spacing = Constants.collectionViewMinimumLineSpacing
    let spaceCumulativeWidth = Double((columnCount - 1)) * spacing
    let itemWidth = (contentSize.width - spaceCumulativeWidth - insets.leading - insets.trailing) / Double(columnCount)
    
    let itemSize = NSCollectionLayoutSize(
        widthDimension: .absolute(itemWidth),
        heightDimension: .absolute(Constants.collectionViewCellHeight)
    )
    let item = NSCollectionLayoutItem(layoutSize: itemSize)
    
    let groupSize = NSCollectionLayoutSize(
        widthDimension: .fractionalWidth(1.0),
        heightDimension: .estimated(2 * Constants.collectionViewCellHeight)
    )
    
    let contentGroup = NSCollectionLayoutGroup.horizontal(
        layoutSize: groupSize,
        subitems: Array(
            repeating: item,
            count: numberOfItems
        )
    )
    contentGroup.interItemSpacing = .fixed(spacing)
    
    let verticalGroupSize = NSCollectionLayoutSize(
        widthDimension: .fractionalWidth(1.0),
        heightDimension: .estimated(2 * Constants.collectionViewCellHeight + Constants.headerHeight + Constants.footerHeight)
    )
    let verticalGroup = NSCollectionLayoutGroup.vertical(
        layoutSize: verticalGroupSize,
        subitems: [contentGroup]
    )
    
    let section = NSCollectionLayoutSection(group: verticalGroup)
    section.interGroupSpacing = spacing
    section.orthogonalScrollingBehavior = .paging
    section.contentInsets = insets

    let headerSize = NSCollectionLayoutSize(
        widthDimension: .fractionalWidth(1.0),
        heightDimension: .absolute(Constants.headerHeight)
    )
    let header = NSCollectionLayoutBoundarySupplementaryItem(
        layoutSize: headerSize,
        elementKind: UICollectionView.elementKindSectionHeader,
        alignment: .top
    )
    header.zIndex = 3
    
    var boundarySupplementaryItems = [header]
    
    if template.hasFooter {
        let footerSize = NSCollectionLayoutSize(
            widthDimension: .fractionalWidth(1.0),
            heightDimension: .absolute(Constants.footerHeight)
        )
        let footer = NSCollectionLayoutBoundarySupplementaryItem(
            layoutSize: footerSize,
            elementKind: UICollectionView.elementKindSectionFooter,
            alignment: .bottom
        )
        footer.zIndex = 3
        
        boundarySupplementaryItems.append(footer)
    }
    
    section.boundarySupplementaryItems = boundarySupplementaryItems
    
    return section
}

So the section has a vertical group, containing a horizontal group. The only reason I did that was to make sure in case this layout only allows headers and footers for the vertical configuration.

Is it possible to have a header and footer with this configuration, without them overlapping? Running this code results in this UI:

Sample 1

Sample 2

See how the UI looks when you run this code.

My goal is to line the header on top, then vertically lower the content, and finally the footer. Why is that not the case, and how to change the code to make that happen?

Upvotes: 0

Views: 52

Answers (0)

Related Questions