41

How can I enable/disable section headers in UICollectionView programmatically?

It can be easily done easily done in Storyboard (checkbox), but how about doing it in code?

Xyand
  • 4,470
  • 4
  • 36
  • 63

5 Answers5

51

You can either use the collectionView:layout:referenceSizeForHeaderInSection: method of the UICollectionViewDelegateFlowLayout and return CGSizeMake(0,0) or set accordingly the headerReferenceSize of UICollectionViewFlowLayout.

Edit: headerReferenceSize is actually the property that storyboard uses to show/hide the headers. I've added the relevant lines from the Storyboard file

With section checkbox on:

 <collectionViewFlowLayout key="collectionViewLayout" minimumLineSpacing="10" minimumInteritemSpacing="10" id="xAt-Uo-bMl">
           <size key="headerReferenceSize" width="50" height="50"/></collectionViewFlowLayout>

With section checkbox off

 <collectionViewFlowLayout key="collectionViewLayout" minimumLineSpacing="10" minimumInteritemSpacing="10" id="xAt-Uo-bMl">
           <size key="headerReferenceSize" width="0" height="0"/></collectionViewFlowLayout>

Edit #2:

From the official docs:

Each section in a flow layout can have its own custom header and footer. To configure the header or footer for a view, you must configure the size of the header or footer to be non zero. You can do this by implementing the appropriate delegate methods or by assigning appropriate values to the headerReferenceSize and footerReferenceSize properties. If the header or footer size is 0, the corresponding view is not added to the collection view.

Bart van Kuik
  • 4,704
  • 1
  • 33
  • 57
spassas
  • 4,778
  • 2
  • 31
  • 39
  • The issue I have is that I change the footer size dynamically. I change the footerReferenceSize in - (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath and make it effective through [self.collectionview performBatchUpdates:^{ //change footerRefernceSize of the Layout } completion:^(BOOL finished) { }]; not working ,it still display the initial value returned by collectionViewLayout referenceSizeForFooterInSection:(NSInteger)section – Hammer Jan 10 '15 at 06:09
  • Amazing that it's a checkbox in storyboard, but you set a height in code. That doesn't add up to me. Oh well, this fixed my issue, which was I don't set a Source for the CollectionView until an async method after ViewDidLoad. This works fine in most CollectionViews, but one with SupplementaryViews won't allow it, so I disabled them from storyboard but then set them after the source was set. – Chucky Aug 25 '16 at 10:55
14

Just change the height to 0 of the headers you don't want to show...

- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section
{
    if (section == 0) {
        return CGSizeZero;
    }else {
        return CGSizeMake(collectionView.frame.size.width,50);
    }
}
AtomicBoolean
  • 1,070
  • 13
  • 19
MiMo
  • 4,905
  • 3
  • 22
  • 23
2

Neither nil nor [UIView new] works an both throw the same error. The best answer is in How to change the UICollectionView footerview's height programatically

Community
  • 1
  • 1
Hammer
  • 8,538
  • 12
  • 44
  • 75
1

All answers I've found on this subject assume that you're using either UICollectionViewFlowLayout or its subclass in which you modify supplementary view's size directly.

I think all of those answers have downsides, especially the ones suggesting modifying header size in layout subclass which creates unnecessary coupling of whatever object manages your data and the layout itself. Also, you have to be careful about your header's constraints, otherwise you'll get bombarded with log messages about breaking constraints if you set the view's size to zero.

Solution that works on every iOS version, whether you're using flow, or compositional layouts.

Just return a valid, empty view.

Create a subclass of UICollectionReusableView

class EmptyCollectionReusableView: UICollectionReusableView {
        
    override func sizeThatFits(_ size: CGSize) -> CGSize {
        var size = super.sizeThatFits(size)
        size.height = .leastNonzeroMagnitude
        
        return size
    }
    
}

register it in your collection view, just like you would with normal supplementary views

let identifier = "emptySupplementaryViewIdentifier"
collectionView.register(EmptyCollectionReusableView.self,
                     forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader,
                     withReuseIdentifier: identifier)

and whenever you want to "hide" header you dequeue it, again just like you would with normal supplementary views:

func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
    
    if shouldHideHeader {
        return collectionView.dequeueReusableSupplementaryView(ofKind: kind,
                                                               withReuseIdentifier: "emptySupplementaryViewIdentifier",
                                                               for: indexPath)
    }
    // Return your normal header
}

When using Diffable data source, insert this code to the supplementaryViewProvider of your Data Source object

Adam
  • 1,776
  • 1
  • 17
  • 28
-4

When you simply don't want an header to appear, in the delegate's

viewForSupplementaryElementOfKind

Just return [UIView new]; when kind == UICollectionElementKindSectionHeader:

- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
{   
    if (kind == UICollectionElementKindSectionHeader) {
       return [UIView new]; // Or even nil, I think it would work.
    }
    ...
    return /*something else that you want to return*/ ;
}
akash
  • 22,664
  • 11
  • 59
  • 87
Afonso Tsukamoto
  • 1,184
  • 1
  • 12
  • 21
  • Thanks. But is there a way to disable headers entirely? Like in the Storyboard designer? What actually happens when headers are disabled in the designer. – Xyand Jul 06 '14 at 04:34
  • That is just a reference, I think. I always managed that by not implementing the datasource/delegate methods if I don't want headers, or by implementing them if I want. I really don't think that there is an actual public property that you can set for that. – Afonso Tsukamoto Jul 06 '14 at 04:38
  • 1
    And if you don't want any section, you can even return 0 in the method numberOfSectionsInCollectionView: – Afonso Tsukamoto Jul 06 '14 at 04:40
  • Setting it to 0 doesn't render any items at all. I just want to get rid of the headers. – Xyand Jul 06 '14 at 08:15
  • You are right. Sorry, it was a bad example. I mean 1 and returning UIView new for the first supplementaryElement. To get rid of the headers, just set it to one section, the section that has all your information, and don't implement the supplementaryElement method or return [UIView new] or nil, that will do it! – Afonso Tsukamoto Jul 06 '14 at 17:46
  • 2
    1. You can't return `nil` 2. I did implement it because most of the time I want the headers. Until I need to disable them. I guess your solution will do. But I'm still curious about the original question. – Xyand Jul 06 '14 at 18:04
  • 3
    Returning `[UIView new]` also doesn't work. It issues an error. – Xyand Jul 08 '14 at 09:09