59

I need a label above every section in my Collection View. I've tried simply dragging a label into my header space above my prototype cell, but every time I run the app, the label is not visible.

Any help?

3 Answers3

97

To add the custom label above every section in UICollectionView, please follow below steps

  1. Enable the section header in UICollectionView

enter image description here

  1. Add a new file of type UICollectionReusableView
  2. In the storyboard change the class of section header in UICollectionViewCell to the newly added file of type UICollectionReusableView.
  3. Add a label in section header of UICollectionViewCell in storyboard
  4. Connect the label in the section header to the UICollectionReusableView file

    class SectionHeader: UICollectionReusableView {
        @IBOutlet weak var sectionHeaderlabel: UILabel!
    }
    
  5. In the ViewController add the below code

    func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
    
        if let sectionHeader = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "SectionHeader", for: indexPath) as? SectionHeader{
            sectionHeader.sectionHeaderlabel.text = "Section \(indexPath.section)"
            return sectionHeader
        }
        return UICollectionReusableView()
    }
    

Here "SectionHeader" is name of the file added to type UICollectionReusableView

Chanchal Raj
  • 3,997
  • 3
  • 38
  • 46
garg
  • 2,465
  • 22
  • 20
  • 2
    Great step by step. The item 6 need a override prefix. – Phuah Yee Keat Nov 10 '18 at 06:56
  • 4
    In 1.,3., & 4. you refer to UICollectionViewCell, however I think it should be UICollectionView. – arcady bob Nov 15 '18 at 21:00
  • 1
    You will need this : https://stackoverflow.com/questions/29282447/unable-to-dequeue-a-cell-with-identifier-cell-must-register-a-nib-or-a-class-f – Kingsley Mitchell May 02 '19 at 01:16
  • You will also need to register the SectionHeader class with the collectionView:-self.collectionView.register(SectionHeader.self, forSupplementaryViewOfKind: kind, withReuseIdentifier: "SectionHeader") – wuf810 Jun 23 '21 at 17:06
  • Shouldn't "SectionHeader" be the reusable identifier set in storyboard? – Eric Apr 22 '22 at 07:24
44

Implement collectionView:viewForSupplementaryElementOfKind:atIndexPath: and supply a dequeued UICollectionElementKindSectionHeader containing your label. If this is a flow layout, be sure also to set the headerReferenceSize or you still won't see anything.

matt
  • 485,702
  • 82
  • 818
  • 1,064
  • 7
    Example code here: https://github.com/mattneub/Programming-iOS-Book-Examples/blob/master/bk2ch08p462collectionViewFlowLayout/ch21p748collectionViewFlowLayout/ViewController.swift – matt May 02 '15 at 17:47
24

If you want a programmatic solution in Swift 4.2, you can do the following:

  1. Setup the UICollectionViewDelegate and UICollectionViewDelegateFlowLayout

  2. Make custom UICollectionReusableView subclasses with whatever views you want defined. Here's one for a header, you can create another for a footer with different characteristics:

    class SectionHeader: UICollectionReusableView {
         var label: UILabel = {
             let label: UILabel = UILabel()
             label.textColor = .white
             label.font = UIFont.systemFont(ofSize: 16, weight: .semibold)
             label.sizeToFit()
             return label
         }()
    
         override init(frame: CGRect) {
             super.init(frame: frame)
    
             addSubview(label)
    
             label.translatesAutoresizingMaskIntoConstraints = false
             label.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
             label.leftAnchor.constraint(equalTo: self.leftAnchor, constant: 20).isActive = true
             label.rightAnchor.constraint(equalTo: self.rightAnchor).isActive = true
        }
    
        required init?(coder aDecoder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
    }
    
  3. Implement the viewForSupplementaryElementOfKind method with the custom views:

    func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView { 
        if kind == UICollectionView.elementKindSectionHeader {
             let sectionHeader = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "header", for: indexPath) as! SectionHeader
             sectionHeader.label.text = "TRENDING"
             return sectionHeader
        } else { //No footer in this case but can add option for that 
             return UICollectionReusableView()
        }
    }
    
  4. Implement the referenceSizeForHeaderInSection and referenceSizeForFooterInSection methods. Header method shown below for example:

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
        return CGSize(width: collectionView.frame.width, height: 40)
    }
    
bradkratky
  • 1,517
  • 1
  • 12
  • 25
Ever Uribe
  • 479
  • 4
  • 13
  • 22
    You need to register the supplementary view - `self.collectionView.register(SectionHeader.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "header")` – brokenrhino May 09 '20 at 04:09