Romowski
Romowski

Reputation: 1548

UICollectionView & custom UICollectionReusableView not works

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

Upvotes: 11

Views: 23592

Answers (7)

Zanael
Zanael

Reputation: 760

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)
    }
}

Upvotes: 1

93sauu
93sauu

Reputation: 4107

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);

Upvotes: 0

Jack
Jack

Reputation: 14329

Xcode 9, Swift 4:

Register UICollectionReusableView in viewDidLoad

self.collectionView.register(UINib(nibName: "DashBoardCollectionReusableView", bundle: nil), forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, withReuseIdentifier: "ReuseIdentifier")

Upvotes: 1

hbk
hbk

Reputation: 11184

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

Upvotes: 1

timurbeg
timurbeg

Reputation: 76

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.

Upvotes: 1

andrewoodleyjr
andrewoodleyjr

Reputation: 3021

  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;
    }
    

Upvotes: 10

Anil Varghese
Anil Varghese

Reputation: 42977

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

Upvotes: 14

Related Questions