41

I have two sections in UICollectionView. I want to show a section header in UICollectionView for only 1st section. Not in 0th section.

So I tried to return nil in viewForSupplementaryElementOfKind: method for section == 0 and returns view for the section == 1.

It crashes and shows below error:

Assertion failure in -[UICollectionView _createPreparedSupplementaryViewForElementOfKind:atIndexPath:withLayoutAttributes:applyAttributes]:

Here it is my code for the supplementary view.

- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
{
    UICollectionReusableView *sectionHeader = nil;
    if (kind == UICollectionElementKindSectionHeader && indexPath.section == 1) {
        sectionHeader = [collectionView dequeueReusableSupplementaryViewOfKind:kind withReuseIdentifier:@"EventSectionHeader" forIndexPath:indexPath];
        sectionHeader.layer.borderWidth = .5f;
        sectionHeader.layer.borderColor = [UIColor colorWithRed:221.0 / 255.0 green:223.0 / 255.0 blue:220.0 / 255.0 alpha:1.0].CGColor;
    }

    return sectionHeader;
}

I have found that returning nil in viewForSupplementaryElementOfKind: method crashing for others too. Other answers suggesting to remove that method.

But I want to show section header for specific sections only. How to achieve that returning view for only one section? Thanks. Any help would be appreciated.

EDIT:

As @san said, I have updated code to hide the section header. It works. It hides the header. But I am still seeing the empty space in the place of section header. Expected results is there should be no space for section header, if it is hidden.

updated code:

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

    UICollectionReusableView *sectionHeader = nil;
    if (kind == UICollectionElementKindSectionHeader) {
        sectionHeader = [collectionView dequeueReusableSupplementaryViewOfKind:kind withReuseIdentifier:@"EventSectionHeader" forIndexPath:indexPath];
        sectionHeader.layer.borderWidth = .5f;
        sectionHeader.layer.borderColor = [UIColor colorWithRed:221.0 / 255.0 green:223.0 / 255.0 blue:220.0 / 255.0 alpha:1.0].CGColor;
        if (indexPath.section == 0) {
            sectionHeader.hidden = YES;

        }else {
            sectionHeader.hidden = NO;
        }
    }

    return sectionHeader;
}

I even tried setting the frame for sectionHeader as @san said. But no luck. same result.

Dinesh Raja
  • 8,345
  • 5
  • 40
  • 78

5 Answers5

84

At last, I found an answer for my question. I have missed something. Anyway sorry for other fellow users.

I set the header height and width inside the below method till now as @san said.

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

But It is not the correct method to set the frame size of supplementary views. Later I found another method inside the flowLayout, which helps me to set the header and footer sizes.

This really works well for me:

- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section
{
    if (section == 0) {
        return CGSizeZero;
    }else {
        return CGSizeMake(CGRectGetWidth(collectionView.bounds), 135);
    }
}

UPDATE: Since someone questioned about my skill in comments, attaching Apple Documentation link for returning CGSizeZero in above method.

Dinesh Raja
  • 8,345
  • 5
  • 40
  • 78
  • 9
    Just FYI, `CGSizeMake(0,0)` can be simplified to `CGSizeZero`. Congratulations on finding the answer! – Mike Buss Nov 25 '13 at 21:21
  • 4
    Unfortunately the same method is not working for me. I'm checking to see if a certain section is empty, the headers don't show as expected but there's about 20px added by every single blank space... – topLayoutGuide Feb 13 '14 at 06:36
  • The used method can be found in UICollectionViewDelegateFlowLayout. See https://developer.apple.com/library/ios/documentation/uikit/reference/UICollectionViewDelegateFlowLayout_protocol/Reference/Reference.html – Lukas Kalinski Jun 03 '14 at 21:37
  • Well this does not help solving my case, where my requirement is to hide the header when 0 records returned. http://stackoverflow.com/questions/27865301/how-to-change-the-uicollectionview-footerviews-height-programatically – Hammer Jan 10 '15 at 06:19
  • 1
    Don't follow this advice. It's very wrong—check out @CaptainRedmuff's answer below. The author should fix this question. This one is wrong—you must return a view from collectionView:viewForSUpplementaryElementOfKind:AtIndexPath: – thefaj May 23 '16 at 19:10
  • 1
    Returning CGSizeZero from referenceSizeForHeaderInSection is wrong. Please mark the correct answer below. This is the wrong way to use UIKit, Dinesh. – thefaj May 26 '16 at 17:37
  • There's no shortage of misinformed iOS developers, Dinesh. Read the Apple docs and stop spreading misinformation. – thefaj Jun 01 '16 at 04:27
  • Ya Dinesh should update this answer to the correct one. – GeneCode Sep 29 '16 at 03:57
  • @thefaj Why not give me a documentation link about what you said? AFAIK, we shouldn't send nil. But, CGSizeZero is the valid instance with zero height & width. That's all. – Dinesh Raja Sep 29 '16 at 04:38
  • Frames cannot have a zero size if you are using self-resizing cells (estimatedItemSize). You'll cause a crash in iOS 9. So this is still not a complete solution to the problem. – dgatwood Feb 22 '17 at 18:19
  • @dgatwood I couldn't understand why self-resizing cells will affect its header size. Cells and headers are unrelated. isn't it? As I already added the documentation link, it clearly says you can send (0,0) in any case. Correct me If I misunderstood. I believe the auto layout constraints you set is going wrong somewhere. If you want to make a header view size (0,0), make the constraints satisfy this size by playing around with priority. – Dinesh Raja Feb 23 '17 at 04:20
  • After looking into it more, I think I was wrong. That temporary hack workaround worked perfectly a few times, then stopped working for no obvious reason. So never mind. – dgatwood Feb 23 '17 at 06:42
23

The documentation for collectionView:viewForSupplementaryElementOfKind:atIndexPath: states:

This method must always return a valid view object. If you do not want a supplementary view in a particular case, your layout object should not create the attributes for that view. Alternatively, you can hide views by setting the hidden property of the corresponding attributes to YES or set the alpha property of the attributes to 0. To hide header and footer views in a flow layout, you can also set the width and height of those views to 0.

Considering you have already tried setting the height to zero and setting the view to be hidden, you should subclass UICollectionViewFlowLayout and implement layoutAttributesForSupplementaryViewOfKind:atIndexPath:

Check the indexPath (as you already do) and return nil if you don't want any layout attributes for that specific supplementary view.

- (UICollectionViewLayoutAttributes *)layoutAttributesForSupplementaryViewOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
{
    if([indexPath section] == 0)
    {
         return nil;
    }

    return [super layoutAttributesForSupplementaryViewOfKind:kind atIndexPath:indexPath];
}
CaptainRedmuff
  • 5,825
  • 2
  • 38
  • 53
  • 2
    This method didn't even getting called when I subclassed the flow layout. I think still I am missing something. Anyway I have added an answer. Really thank you captain for your time. – Dinesh Raja Nov 20 '13 at 12:14
  • This is also wrong. You cannot return nil for this method. – GeneCode Sep 29 '16 at 03:57
  • This may be the case in more recent versions of iOS but back in 2013, iOS 6/7 returning `nil` from `layoutAttributesForSupplementaryViewOfKind` was entirely valid. – CaptainRedmuff Sep 29 '16 at 10:53
9

Documentation clearly says -

Return Value

A configured supplementary view object. You must not return nil from this method.

So you need follow -

This method must always return a valid view object. If you do not want a supplementary view in a particular case, your layout object should not create the attributes for that view. Alternatively, you can hide views by setting the hidden property of the corresponding attributes to YES or set the alpha property of the attributes to 0. To hide header and footer views in a flow layout, you can also set the width and height of those views to 0.

Coming to your code, below snippet should work for you:

- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
{
    UICollectionReusableView *sectionHeader = nil;
    if (kind == UICollectionElementKindSectionHeader) {
        sectionHeader = [collectionView dequeueReusableSupplementaryViewOfKind:kind withReuseIdentifier:@"EventSectionHeader" forIndexPath:indexPath];

        if(indexPath.section == 1)
          {
             sectionHeader.layer.borderWidth = .5f;
             sectionHeader.layer.borderColor = [UIColor colorWithRed:221.0 / 255.0 green:223.0 / 255.0 blue:220.0 / 255.0 alpha:1.0].CGColor;
          }
        else
        {
          sectionHeader.frame = CGRectZero;
          sectionHeader.hidden = YES;
        }
    }

    return sectionHeader;
}
San
  • 1,766
  • 13
  • 22
  • I got it @san.. Thanks.. once I tried, I will check it as answer. – Dinesh Raja Nov 18 '13 at 08:31
  • Is there any method to return height and width of header and footer? – Dinesh Raja Nov 18 '13 at 08:31
  • Set appropriate sectionHeader.frame.size.width and sectionHeader.frame.size.height – San Nov 18 '13 at 08:37
  • Setting header frame in viewForSupplementaryElementOfKind is not working.. setting hidden just hides the view. but it is still showing the empty space of a header view. – Dinesh Raja Nov 18 '13 at 10:19
  • Set the width and height as 0 for that view. Check my updated answer. – San Nov 18 '13 at 10:22
  • 1
    I have did that exactly.. no improvement.. Still shows empty space in the section header 0. – Dinesh Raja Nov 18 '13 at 10:26
  • Sam. setting frame size here is not working . I also tried 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 . It is not working as well. – Hammer Jan 10 '15 at 06:17
  • From my experience footerReferenceSize and headerReferenceSize are working. You just need to set UICollectionViewDelegateFlowLayout. – Skodik.o Jun 12 '18 at 08:48
0

In my case I have given inset to sections so it was giving me empty space So if you have implemented following method, do it in below way

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
        if <condition for which you want to hide section>{
            return UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
        }else{
            return UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
        }
    }
Nikunj Acharya
  • 643
  • 6
  • 17
-1

You can hide/show your reusable header section by adding UICollectionViewDelegateFlowLayout delegate and using below code

- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section{
if (self.isForSearch) { //---> for hiding
    return CGSizeMake(0,0);
}
else{//---> for showing
    return ((UICollectionViewFlowLayout*)self.collectionChoosePlanView.collectionViewLayout).headerReferenceSize;
}
}

So you can hide/show it

UdayM
  • 1,613
  • 11
  • 31
Kaan Esin
  • 70
  • 7