33

There is a method to get a cell by indexPath (UICollectionView cellForItemAtIndexPath:). But I can"t find a method to get one of the supplementary views like a header or footer, after it has been created. Any ideas?

Emil
  • 7,220
  • 17
  • 76
  • 135
Dorian Roy
  • 3,094
  • 2
  • 31
  • 51

4 Answers4

50

UPDATE

As of iOS 9, you can use -[UICollectionView supplementaryViewForElementKind:atIndexPath:] to get a supplementary view by index path.

ORIGINAL

Your best bet is to make your own dictionary mapping index paths to supplementary views. In your collectionView:viewForSupplementaryElementOfKind:atIndexPath: method, put the view into the dictionary before returning it. In your collectionView:didEndDisplayingSupplementaryView:forElementOfKind:atIndexPath:, remove the view from the dictionary.

rob mayoff
  • 375,296
  • 67
  • 796
  • 848
  • 1
    Thanks for pointing me to the didEndDisplayingSupplementaryView method! I missed that one. – Dorian Roy Nov 16 '12 at 09:45
  • 13
    Is there a good reason that the UICollectionView doesn't offer an API for this? – CharlieMezak Apr 10 '13 at 19:59
  • I am pretty sure Apple will refactor UICollectionView stuff to make it more similar than UITableView, lot of features are still missing – Thomas Decaux Sep 27 '13 at 10:44
  • The reason is that CollectionView is more generic than a table view. With CollectionViews, there are only cells, supplementary views and decoration views. Headers and footers are actually implemented as supplementary views: so actually it wouldn't make sense for Apple to explicitly offer an API for what really is a *specific* kind of supplementary view. – fatuhoku Apr 06 '14 at 20:36
  • 11
    iOS 9 introduces `func supplementaryViewForElementKind(elementKind: String, atIndexPath indexPath: NSIndexPath) -> UICollectionReusableView` :) – hagi Aug 11 '15 at 09:58
  • 1
    Also added iOS 9 public func visibleSupplementaryViewsOfKind(elementKind: String) -> [UICollectionReusableView] – dzensik Jan 18 '16 at 18:16
  • what should be the `indexpath`? If I have a header in `first section`, so the index path would be `[NSIndexPath indexPathForRow:0 inSection:0]`? – nr5 Oct 04 '17 at 18:17
31

I would like to share my insight of the solution provided by rob mayoff but I can't post comment so I am putting it here:

For every one of you that tried to keep reference of the supplementary views being used by a collection view but who run into issues of loosing track too early because of

collectionView:didEndDisplayingSupplementaryView:forElementOfKind:atIndexPath:

being called too many times, try using an NSMapTable instead of a dictionary.

I use

@property (nonatomic, strong, readonly) NSMapTable *visibleCollectionReusableHeaderViews;

created like this:

_visibleCollectionReusableHeaderViews = [NSMapTable mapTableWithKeyOptions:NSMapTableStrongMemory valueOptions:NSMapTableWeakMemory];

so that when you are keeping a reference to a supplementary view:

- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
{
    // ( ... )
    [_visibleCollectionReusableHeaderViews setObject:cell forKey:indexPath];

it keeps only a WEAK reference to it in the NSMapTable and it keeps it AS LONG AS the object is not deallocated!

You don't need anymore to remove the view from

collectionView:didEndDisplayingSupplementaryView:forElementOfKind:atIndexPath:

as the NSMapTable will lose the entry as soon as the view is deallocated.

Bluezen
  • 850
  • 9
  • 13
  • Thank you for this great idea. It led me to NSHashTable which allows me to keep weak references to the header views without needing to keep keys in synch when sections are moved within the table. – David U Jan 26 '15 at 20:24
  • @DavidU if you don’t have keys, how do you find the supplementary view you need? Or do you have another means of identifying them? – Zev Eisenberg Jul 31 '15 at 19:00
  • @DavidU I ended up overriding `-applyLayoutAttributes` and grabbing a copy of the index path, and then iterating over views in the hash table and comparing against the index path. – Zev Eisenberg Jul 31 '15 at 19:49
  • @ZevEisenberg I give each header a unique tag and then enumerate over them in a headerWithTag method. – David U Aug 03 '15 at 14:03
  • @DavidU cool, sounds like we have similar approaches. Also: collection view really ought to have API for this :\ – Zev Eisenberg Aug 03 '15 at 14:17
9

First thing you have to do is check the box "Section Header" in the collection view's attribute inspector. Then add a collection reusable view just like you added your cell to the collection view, write an identifier and make a class for it if you need to. Then implement the method:

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

From there do exactly like you did with cellForItemAtIndexPath Its also important to specify if its a header or footer you are coding about:

if([kind isEqualToString:UICollectionElementKindSectionHeader])
{
    Header *header = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"headerTitle" forIndexPath:indexPath];
    //modify your header
    return header;
}

else
{

    EntrySelectionFooter *footer = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionFooter withReuseIdentifier:@"entryFooter" forIndexPath:indexPath];
    //modify your footer
    return footer;
}

use indexpath.section to know what section this is in also note that Header and EntrySelectionFooter are custom subclasses of UICollectionReusableView that I made

Cœur
  • 37,241
  • 25
  • 195
  • 267
Alex
  • 451
  • 5
  • 13
  • 3
    `kind` is an `NSString`. It should be compared using `if ([kind isEqualToString:UICollectionElementKindSectionHeader])`, not `==`. – Aaron Brager Aug 12 '14 at 01:39
3

This method is often enough to serve the purpose of reloading on-screen supplementary views:

collectionView.visibleSupplementaryViews(ofKind: UICollectionElementKindSectionHeader)
ullstrm
  • 9,812
  • 7
  • 52
  • 83
  • 1
    Swift 4: collectionView.visibleSupplementaryViews(ofKind: UICollectionView.elementKindSectionHeader) – Trevor Feb 17 '19 at 00:51