10

I'm trying to use custom UICollectionReusableView (which has own class and XIB) in my UICollectionView header. But after fetching data in the place of header I have nothing.

My steps:

  1. Registering class in viewDidLoad:

     [self.collectionView registerClass:[CollectionViewHeader class] 
      forSupplementaryViewOfKind: UICollectionElementKindSectionHeader 
      withReuseIdentifier:@"HeaderView"];
    
  2. Trying to show:

    - (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
    {
    UICollectionReusableView *reusableView = nil;
    
    if (kind == UICollectionElementKindSectionHeader) {
        CollectionViewHeader *collectionHeader = [self.collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"HeaderView" forIndexPath:indexPath];
    
        NSInteger section = [indexPath section];
        id <NSFetchedResultsSectionInfo> sectionInfo = [fetchRecipes sections][section];
        collectionHeader.headerLabel.text = @"bla-bla-bla";
    
        reusableView = collectionHeader;
    }
    
    return reusableView;
    }
    

Can anybody tell me what's wrong? ) Thanks for any advice

Anil Varghese
  • 41,329
  • 9
  • 90
  • 110
Romowski
  • 1,448
  • 4
  • 23
  • 47

7 Answers7

14

I think you are adding label to the xib. So you need to registerNib: for the header view instead of registerClass:

Anil Varghese
  • 41,329
  • 9
  • 90
  • 110
10
  1. Register Your header nib/xib in the viewDidLoad section.

    [self.collectionView registerNib:  [UINib nibWithNibName:@"headerCollectionViewCell" bundle:nil] forCellWithReuseIdentifier:@"headerCell"]; 
    
  2. Create the custom supplementary view cell.

    - (headerCollectionViewCell *)collectionView:(UICollectionView *)collectionViews viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
    {
        UICollectionReusableView *reusableView = nil;
    
        if (kind == UICollectionElementKindSectionHeader) {
    
            UINib *nib = [UINib nibWithNibName:@"headerCollectionViewCell" bundle:nil];
    
            [collectionViews registerNib:nib forCellWithReuseIdentifier:@"headerCell"];
    
            headerCollectionViewCell *collectionHeader = [collectionViews dequeueReusableCellWithReuseIdentifier:@"headerCell" forIndexPath:indexPath];
            collectionHeader.titleLabel.text = @"What";
    
            reusableView = collectionHeader;
       }
    
       return reusableView;
    }
    
andrewoodleyjr
  • 2,703
  • 2
  • 17
  • 19
  • 7
    You're using `registerNib:forCellWithReuseIdentifier:`. You should be using `registerNib:forSupplementaryViewOfKind:withReuseIdentifier:` – Gabriel Osorio Dec 11 '14 at 19:49
  • Use cells for the grid items and supplementary views for headers/footers. More [here](http://nshipster.com/uicollectionview/#supplementary-views). Also, [this post](http://www.raywenderlich.com/22324/beginning-uicollectionview-in-ios-6-part-12) is a bit old, but it has some good diagrams and examples of semantic uses of the different elements of the UICollectionView. Hope that clears it up a bit. – Gabriel Osorio Feb 10 '15 at 18:11
  • And with adding this to viewDidLoad you do not have to add it again in delegate function. 10x @gabriel-osorio you are right. – Lachezar Todorov Nov 27 '15 at 16:32
  • Please Andrew edit your answer, without Gabriel's comment it's useless. – Lachezar Todorov Nov 27 '15 at 16:35
  • Please use below code for Header and Footer view in UICollectionView `[self.selectionCollectionView registerNib:[UINib nibWithNibName:@"FlootThumbnailCollectionReusableView" bundle:nil] forCellWithReuseIdentifier:@"HeaderView"];` – Anil Gupta Feb 03 '17 at 11:00
1

Just in case if someone needs solution. You don't have to register the header class using

[self.collectionView registerClass:...]

Just use the layout's delegate method to return the header class.

Tobi Nary
  • 4,387
  • 4
  • 26
  • 48
timurbeg
  • 76
  • 6
1

Actually there is can be few reasons:

  1. (most common) If u add u'r suplementaryView in storyboard, and then try to register class

    [self.stickyCollectionView registerClass:[<CLASSFORSUPPLEMENTARYVIEWW> class]
              forSupplementaryViewOfKind:UICollectionElementKindSectionHeader
                     withReuseIdentifier:NSStringFromClass([<CLASSFORSUPPLEMENTARYVIEWW> class])];
    

u will get suplementaryView, but not that u create (standard one) - u will see obj, but actually this is will be like placeholder.

Example:

enter image description here

Here u can see that obj was created, but outlets are nil (in this simple case only one outlet - _monthNameLabel).

  1. I see few times this problem also

If u create separate Obj for handling dataSourse/delegate for collectionView and add reference outlet to it, and in init methods try to register class to u'r outlet (assumed that view created in separate nib file), u will also receive same result like previous, but reason another - u'r outlet is nil here:

enter image description here

As solution u for example can use custom setter for this like:

#pragma mark - CustomAccessors

- (void)setcCollectionView:(UICollectionView *)collectionView
{
    _collectionView = collectionView;

    [self.stickyCollectionView registerNib:...];
}
  1. as suggested by @Anil Varghese

u can use registerClass instead of registerNib

hbk
  • 9,872
  • 9
  • 82
  • 110
1

Xcode 9, Swift 4:

Register UICollectionReusableView in viewDidLoad

self.collectionView.register(UINib(nibName: "DashBoardCollectionReusableView", bundle: nil), forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, withReuseIdentifier: "ReuseIdentifier")
Jack
  • 10,795
  • 4
  • 65
  • 90
1
class CustomFlowLayout: UICollectionViewFlowLayout {

    override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
        let attributesForElementsInRect = super.layoutAttributesForElements(in: rect)
        var newAttributesForElementsInRect = [UICollectionViewLayoutAttributes]()

        for attributes in attributesForElementsInRect! {

            if !(attributes.representedElementKind == UICollectionElementKindSectionHeader
                || attributes.representedElementKind == UICollectionElementKindSectionFooter) {

                // cells will be customise here, but Header and Footer will have layout without changes.
            }

            newAttributesForElementsInRect.append(attributes)
        }

        return newAttributesForElementsInRect
    }
}


class YourViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        let headerNib = UINib.init(nibName: "HeaderCell", bundle: nil)
        collectionView.register(headerNib, forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, withReuseIdentifier: "HeaderCell")

        let footerNib = UINib.init(nibName: "FooterCell", bundle: nil)
        collectionView.register(footerNib, forSupplementaryViewOfKind: UICollectionElementKindSectionFooter, withReuseIdentifier: "FooterCell")
    }


    func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {

        switch kind {
        case UICollectionElementKindSectionHeader:
            let headerView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "HeaderCell", for: indexPath) as! HeaderCell
            return headerView
        case UICollectionElementKindSectionFooter:
            let footerView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "FooterCell", for: indexPath) as! FooterCell
            return footerView
        default:
            return UICollectionReusableView()
        }
    }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
        return CGSize(width: collectionView.frame.width, height: 45)
    }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForFooterInSection section: Int) -> CGSize {
        return CGSize(width: collectionView.frame.width, height: 25)
    }
}
Zanael
  • 632
  • 5
  • 10
0

You was registering correctly the class and the delegate is implemented correctly.

The problem can be that the flow layout (by default) is not configured for header view, do you have this line in the code or interface file?

UICollectionViewFlowLayout *flowLayout = (UICollectionViewFlowLayout *)_collectionView.collectionViewLayout;
flowLayout.headerReferenceSize = CGSizeMake(CGRectGetWidth(_collectionView.bounds), 100);
93sauu
  • 2,762
  • 3
  • 19
  • 39