5

I wish to add a label to my UICollectionView programmatically, and have used the viewForSupplementaryElementOfKind and referenceSizeForHeaderInSection to set it up, however for some reason when I setup my views it is still placing it inside the first row of my CollectionView instead of the created header. As you can see in this screenshot, "Today" is in the first cell, instead of the header I created for it

class TvController: UICollectionViewController, UICollectionViewDelegateFlowLayout {

private let cellId = "cellId"
private let headerId = "headerId"

override func viewDidLoad() {
    super.viewDidLoad()

    navigationItem.title = "TV"
    navigationController?.navigationBar.isTranslucent = false

    collectionView?.backgroundColor = .white

    collectionView?.register(TvCell.self, forCellWithReuseIdentifier: cellId)
    collectionView?.register(Header.self, forCellWithReuseIdentifier: headerId)

}

override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return 10
}

override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cellId", for: indexPath)

    return cell
}

//Row for each TV show
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
    return CGSize(width: view.frame.width, height: 120)
}

//Today's date header
override func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
    let header = collectionView.dequeueReusableCell(withReuseIdentifier: headerId, for: indexPath) as! Header

    return header
}

//Today's date header
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
    return CGSize(width: view.frame.width, height: 60)
}
}

Here is the Header class

class Header: UICollectionViewCell  {

override init(frame: CGRect)    {
    super.init(frame: frame)
    setupHeaderViews()
}

let dateLabel: UILabel = {
    let title = UILabel()
    title.text = "Today"
    title.textColor = .gray
    title.backgroundColor = .black
    title.font = UIFont(name: "Montserrat", size: 17)
    title.translatesAutoresizingMaskIntoConstraints = false
    return title
}()

func setupHeaderViews()   {
    addSubview(dateLabel)

    dateLabel.leftAnchor.constraint(equalTo: leftAnchor, constant: 20).isActive = true
    dateLabel.topAnchor.constraint(equalTo: topAnchor, constant: 10).isActive = true
    dateLabel.widthAnchor.constraint(equalToConstant: 120).isActive = true
    dateLabel.heightAnchor.constraint(equalToConstant: 30).isActive = true
}


required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}
}
Rishad Appat
  • 1,786
  • 1
  • 15
  • 30
unicorn_surprise
  • 951
  • 2
  • 21
  • 40

2 Answers2

9

You're using the wrong method to register your header. You're also dequeuing using the wrong method. Since you're registering your header as a forSupplementaryViewOfKind -- You have to use deque the header using 'dequeueReusableSupplementaryView' method instead of 'dequeueReusableCell'

 override func viewDidLoad() {
    collectionView?.register(Header.self, forSupplementaryViewOfKind:
       UICollectionElementKindSectionHeader, withReuseIdentifier: headerId)
  }


override func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind:
    String, at indexPath: IndexPath) -> UICollectionReusableView {
        let header = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier:
            headerId, for: indexPath) as! Header
        return header
}
antdwash
  • 516
  • 4
  • 10
  • Thanks antwash for your answer, it seems now I get an error in the build. It states: Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'could not dequeue a view of kind: UICollectionElementKindCell with identifier headerId - must register a nib or a class for the identifier or connect a prototype cell in a storyboard' Do you know what I would have to do now? – unicorn_surprise Nov 09 '17 at 04:59
  • Check out the edit, it shows what you should have in the viewDidLoad and your viewForSupplementaryElementOfKind methods. Hope you understand :) – antdwash Nov 09 '17 at 06:25
  • Ahhh I see, sorry about that, I'm still learning :) Thanks so much for your help! I understand now. – unicorn_surprise Nov 09 '17 at 07:09
  • No worries, I'm 5 months into ios and learning more and more every day =] – antdwash Nov 09 '17 at 07:24
0
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
    let headerView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "HeaderId", for: indexPath) as! HeaderClassname
    switch kind {
    case UICollectionElementKindSectionHeader:
        if indexPath.section == 0 {
            //Your Code Here
        } else {
        }
        return headerView

    default:
        assert(false, "Unexpected element kind")
    }

    return headerView
}
Ravi Dhorajiya
  • 1,531
  • 3
  • 21
  • 26
Amul4608
  • 1,390
  • 14
  • 30