1

When using a UICollectionView with a UICollectionViewFlowLayout that has sectionHeadersPinToVisibleBounds set to true the sticky headers will be positioned incorrectly when a UIRefreshControl added to the collection view is refreshing.

Example view controller:

import UIKit

public final class StickyHeaderTestViewController: UICollectionViewController {
    init() {
        let layout = UICollectionViewFlowLayout()
        layout.sectionHeadersPinToVisibleBounds = true

        super.init(collectionViewLayout: layout)
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override public func viewDidLoad() {
        super.viewDidLoad()

        collectionView.backgroundColor = .white
        collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "UICollectionViewCell")
        collectionView.register(UICollectionReusableView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "UICollectionReusableView")

        let refreshControl = UIRefreshControl()
        refreshControl.addTarget(self, action: #selector(refreshControlValueChanged(_:)), for: .valueChanged)
        collectionView.refreshControl = refreshControl
    }

    override public func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

        let layout = collectionView.collectionViewLayout as! UICollectionViewFlowLayout
        layout.itemSize = CGSize(width: view.bounds.width, height: 40)
        layout.headerReferenceSize = CGSize(width: view.bounds.width, height: 40)
    }

    override public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "UICollectionViewCell", for: indexPath)
        switch indexPath.section {
        case 0:
            cell.backgroundColor = .blue
        case 1:
            cell.backgroundColor = .yellow
        case 2:
            cell.backgroundColor = .blue
        default:
            break
        }
        return cell
    }

    override public func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
        let view = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "UICollectionReusableView", for: indexPath)
        switch indexPath.section {
        case 0:
            view.backgroundColor = .brown
        case 1:
            view.backgroundColor = .green
        case 2:
            view.backgroundColor = .brown
        default:
            break
        }
        return view
    }

    override public func numberOfSections(in collectionView: UICollectionView) -> Int {
        3
    }

    override public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        10
    }

    @objc private func refreshControlValueChanged(_ sender: UIRefreshControl) {
        DispatchQueue.main.asyncAfter(deadline: .now() + 10) {
            sender.endRefreshing()
        }
    }
}

Is there a workaround for this issue?

Offset sticky header

Joseph Duffy
  • 4,566
  • 9
  • 38
  • 68
  • Did you find a fix or a workaround? The problem seems to be positioning header when collectionsView's top content inset is more than 0. The header sticky zero position takes content inset into account. – virusss8 Nov 18 '21 at 08:27

0 Answers0