BLACK FRIDAY SALE: Save 50% on all my Swift books and bundles! >>

SOLVED: [Swift5/iOS13+/UIKit] UICollectionView & DiffableDataSource & flowLayout: how to add a header?

Forums > iOS

No Storyboard! I have a collectionView with a diffeable datasource. Only one section. I want to display a header, so I registered a custom cell class:

collectionView.register(SectionHeader.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: SectionHeader.reuseidentifier)

I create a flow Layout as such:

    private func createFlexibleFlowLayout(in view: UIView) -> UICollectionViewFlowLayout {
        let width = view.bounds.width
        let padding: CGFloat = 12
        let minimumItemSpacing: CGFloat = 10
        let availableWidth = width - (padding * 2) - (minimumItemSpacing * 2)

        let itemWidth = traitCollection.horizontalSizeClass == .compact ? availableWidth / 2 : availableWidth / 3

        let flowLayout = UICollectionViewFlowLayout()
        flowLayout.sectionInset = UIEdgeInsets(top: padding, left: padding, bottom: padding, right: padding)
        flowLayout.itemSize = CGSize(width: itemWidth, height: itemWidth + 40)

        flowLayout.sectionHeadersPinToVisibleBounds = true

        return flowLayout

The datasource looks as follows:

    func createDataSource() {
        dataSource = UICollectionViewDiffableDataSource<Section, Project>(collectionView: collectionView) { (collectionView, indexPath, project) in
                return self.configure(NormalProjectCell.self, with: project, for: indexPath)

        dataSource?.supplementaryViewProvider = { (collectionView, kind, indexPath) in
            guard let sectionHeader = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: SectionHeader.reuseidentifier, for: indexPath) as? SectionHeader else {
                fatalError("Could not dequeue sectionHeader: \(SectionHeader.reuseidentifier)")

            sectionHeader.title.text = "Tap and hold to edit an existing Project!"
            sectionHeader.subtitle.text = "tap to view Project notes"
            return sectionHeader

But how and where do I add the header? The 'old way' doesn't work:

override func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {(...)}

I'm stumped!



Maybe you are missing the height for that Header?

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {


@twostraws  Site AdminHWS+

If you haven't already watched my video on this stuff, you might want to consider doing so:


@twostraws I have! Excellent video. Had some troubles with the sections so I switched back from compositional layout (I had the headers working there) to flow layout. That's where I can't get the header. But I solved it by doing it differently (no header) ...


Using the SectionHeader class from Paul's video mentioned above I came up with this conversion for your code example. Would this work for you?

private func setupCollectionViewWithCompostionalLayout() {
        // Adjust width and height as needed
        let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(0.33), heightDimension: .fractionalHeight(0.5))
        let item = NSCollectionLayoutItem(layoutSize: itemSize)

        // Adjust height and item spacing as needed
        let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .absolute(60))
        let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item])
        group.interItemSpacing = .fixed(10)

        let section = NSCollectionLayoutSection(group: group)
        section.contentInsets = NSDirectionalEdgeInsets(top: 12, leading: 12, bottom: 12, trailing: 12)

        // This is where the header gets added:
        let headerSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .absolute(50))
        let header = NSCollectionLayoutBoundarySupplementaryItem(layoutSize: headerSize, elementKind: UICollectionView.elementKindSectionHeader, alignment: .top)
        section.boundarySupplementaryItems = [header]

        let layout = UICollectionViewCompositionalLayout(section: section)

        collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
        collectionView.register(YourCellClassHere.self, forCellWithReuseIdentifier: "cellID")
        collectionView.register(SectionHeader.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: SectionHeader.reuseIdentifier)


            collectionView.topAnchor.constraint(equalTo: view.topAnchor),
            collectionView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            collectionView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            collectionView.bottomAnchor.constraint(equalTo: view.bottomAnchor)


Thanks for taking the effort to sort this out!


Hacking with Swift is sponsored by Guardsquare

SPONSORED AppSweep by Guardsquare helps developers automate the mobile app security testing process with fast, free scans. By using AppSweep’s actionable recommendations, developers can improve the security posture of their apps in accordance with security standards like OWASP.

Learn more

Sponsor Hacking with Swift and reach the world's largest Swift community!

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

All interactions here are governed by our code of conduct.

Unknown user

You are not logged in

Log in or create account

Link copied to your pasteboard.