How to add HeaderView in UICollectionView like UITableView's tableHeaderView

Solution 1:

self.collectionView  =  [[UICollectionView alloc] initWithFrame:CGRectMake(0, 0, 320, self.view.frame.size.height) collectionViewLayout:flowlayout];
self.collectionView.contentInset = UIEdgeInsetsMake(50, 0, 0, 0);
UIImageView *imagev = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@"015.png"]];
imagev.frame = CGRectMake(0, -50, 320, 50);
[self.collectionView addSubview: imagev];
[self.view addSubview: _collectionView];

I use the attribute contentInset to insert a frame to the top of the UICollectionView, then I add the image view to it, and it succeeds. I think it can act excactly as UITableView's tableHeaderView property. What do you think?

Solution 2:

I've put a view at the top of a collection view by just adding a UIView as a subview of the collection view. It does scroll up with the collection view and it has normal UIView user interaction. This works ok if you have no section header, but doesn't work if you do. In that situation, I don't see anything wrong with the way you're doing it. I'm not sure why you're not detecting touches, they work fine for me.

Solution 3:

Since iOS 13 a canonical way to set the header is to use UICollectionViewCompositionalLayoutConfiguration

This way allows setting boundarySupplementaryItems per section or globally for a collection view.

let headerSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .estimated(44))

let header = NSCollectionLayoutBoundarySupplementaryItem(layoutSize: headerSize, elementKind: "header", alignment: .top)

let config = NSCollectionViewCompositionalLayoutConfiguration()
config.boundarySupplementaryItems = [header]

let layout = UICollectionViewCompositionalLayout(sectionProvider: sectionProvider, configuration: config)

return layout

To learn more visit the official documentation at: https://developer.apple.com/documentation/appkit/nscollectionviewcompositionallayoutconfiguration

Solution 4:

I ended up using a UICollectionView extension to add my custom header. Using a specific tag, I'm able to fake the stored property to identify my custom header (all transparent from outside). You might have to scroll to a specific offset if the layout of the UICollectionView is not completed when you add your custom header.

extension UICollectionView {
    var currentCustomHeaderView: UIView? {
        return self.viewWithTag(CustomCollectionViewHeaderTag)
    }

    func asssignCustomHeaderView(headerView: UIView, sideMarginInsets: CGFloat = 0) {
        guard self.viewWithTag(CustomCollectionViewHeaderTag) == nil else {
            return
        }
        let height = headerView.systemLayoutSizeFitting(UILayoutFittingCompressedSize).height
        headerView.frame = CGRect(x: sideMarginInsets, y: -height + self.contentInset.top, width: self.frame.width - (2 * sideMarginInsets), height: height)
        headerView.tag = CustomCollectionViewHeaderTag
        self.addSubview(headerView)
        self.contentInset = UIEdgeInsets(top: height, left: self.contentInset.left, bottom: self.contentInset.bottom, right: self.contentInset.right)
    }

    func removeCustomHeaderView() {
        if let customHeaderView = self.viewWithTag(CustomCollectionViewHeaderTag) {
            let headerHeight = customHeaderView.frame.height
            customHeaderView.removeFromSuperview()
            self.contentInset = UIEdgeInsets(top: self.contentInset.top - headerHeight, left: self.contentInset.left, bottom: self.contentInset.bottom, right: self.contentInset.right)
        } 
    }
}

CustomCollectionViewHeaderTag refers to the tag number you give to your header. Make sure it is not the tag of anotherView embedded in your UICollectionView.

Solution 5:

The best way to achieve this is to make a section header for the first section. Then set the UICollectionViewFlowLayout's property:

@property(nonatomic) BOOL sectionHeadersPinToVisibleBounds

or swift

var sectionHeadersPinToVisibleBounds: Bool

to NO (false for swift). This will ensure that the section header scrolls continuously with the cells and does not get pinned to the top like a section header normally would.