40

I have a UICollectionView. I would like to add a header. My header would only be a UILabel. I've :

1) selected "Section Header" as a Collection View accessory in the IB.

2) created a Collection Reusable View in the IB, on the side, declared as collectionViewHeader.

3) added those lines :

- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
{
    if (kind == UICollectionElementKindSectionHeader) {

            return collectionViewHeader;
    }
    return nil;
}

But they are never called.

Do I have to create a class just for that label in order to use

[self.collectionView registerClass:[UICollectionReusableView class] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"header"];

?

Why isn't it as simple as the UITableView where you just drag and drop whatever header you want ?! Things are so complicated with UICollectionView...

Nicolas Roy
  • 3,453
  • 5
  • 22
  • 40

3 Answers3

54

In swift like below

Register Header View

collectionView.register(HeaderView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "headerView")

In UICollectionViewDataSource

func collectionView(collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, atIndexPath indexPath: NSIndexPath) -> UICollectionReusableView {

    let headerView = collectionView.dequeueReusableSupplementaryViewOfKind(UICollectionElementKindSectionHeader, withReuseIdentifier: "headerView", forIndexPath: indexPath)

    headerView.frame.size.height = 100

    return headerView
}

Important is that you are supply the flow layout with the header size

flowLayout.headerReferenceSize = CGSize(width: self.collectionView.frame.size.width, height: 100)

Otherwise the data source method will not get called

Ever Uribe
  • 399
  • 3
  • 12
Eike
  • 1,951
  • 17
  • 31
  • Should Header View be UICollectionReusableView? – Michał Ziobro Oct 01 '18 at 10:02
  • 1
    viewForSupplementaryElementOfKind this is in UICollectionViewDataSource not UICollectionViewDelegate – Michał Ziobro Oct 01 '18 at 10:14
  • 1
    instead of headerReferenceSize can also be implemented this method func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize – Michał Ziobro Oct 01 '18 at 10:17
24

If you don't set the header view in storyboard, you will have to register nib.

Example in viewDidLoad:

- (void)viewDidLoad
{
    [self.collectionView registerClass:NSStringFromClass([YourOwnSubClass class]) forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"HeaderViewIdentifier"];
}

Anyway, you can also subclass UICollectionReusableView.

@interface YourOwnSubClass : UICollectionReusableView

then call delegate in your class example:

- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView
           viewForSupplementaryElementOfKind:(NSString *)kind
                                 atIndexPath:(NSIndexPath *)indexPath
{

    YourOwnSubClass *headerView = [collectionView dequeueReusableSupplementaryViewOfKind:
                                         UICollectionElementKindSectionHeader withReuseIdentifier:@"HeaderView" forIndexPath:indexPath];    
    [self updateSectionHeader:headerView forIndexPath:indexPath];

    return headerView;
}

- (void)updateSectionHeader:(UICollectionReusableView *)header forIndexPath:(NSIndexPath *)indexPath
{
    NSString *text = [NSString stringWithFormat:@"header #%i", indexPath.row];
    header.label.text = text;
}

And don't forget to set header size in collection view or in flow layout so header view will be visible.

Arnlee Vizcayno
  • 2,374
  • 3
  • 20
  • 31
Raz
  • 2,603
  • 1
  • 20
  • 40
  • 1
    Thank's for your answer. Unfortunately the collectionView:viewForSupplementaryElementOfKind:atIndexPath is not called. And do you know how to add a nib to YourOwnSubClass ? – Nicolas Roy Feb 12 '14 at 16:02
  • then perhaps you forgot to set your self as delegate? What do you mean? add a nib as a subview? or initialize YourOwnSubClass from nib? – Raz Feb 12 '14 at 16:07
  • Delegate is set, everything else works fine :/ I mean initialize YourOwnSubClass from nib, as it is a UICollectionReusableView. – Nicolas Roy Feb 12 '14 at 16:12
  • YourOwnSubClass *sub = [[[NSBundle mainBundle] loadNibNamed:@"XibOrNibName" owner:self options:nil] lastObject]; – Raz Feb 12 '14 at 16:18
  • It is not a Delegate, but a DataSource method. – Darius Miliauskas Oct 23 '18 at 09:45
  • 2
    You need to set flowLayout.headerReferenceSize in order to get the method to be called. – Darius Miliauskas Oct 23 '18 at 09:52
  • can header view be the type of UIStackView or UIView ? I am getting error if I used the headerView is the type of UIView. 'Value of type 'UIView' has no member 'dequeueReusableSupplementaryView' – Pratik Sep 27 '19 at 01:28
2

None of above works if you forgot to enable accessory in your XIB file, don't forget to activate your desired section!

enter image description here

woheras
  • 31
  • 1
  • 2