UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

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: https://www.youtube.com/watch?v=SR7DtcT61tA


@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!


BUILD THE ULTIMATE PORTFOLIO APP Most Swift tutorials help you solve one specific problem, but in my Ultimate Portfolio App series I show you how to get all the best practices into a single app: architecture, testing, performance, accessibility, localization, project organization, and so much more, all while building a SwiftUI app that works on iOS, macOS and watchOS.

Get it on Hacking with Swift+

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.