Hitit
Hitit

Reputation: 478

How to get IndexPath for UICollectionView Header?

View: HeaderView

class HeaderCell: UICollectionViewCell {
    //MARK: - Properties

....

    lazy var clearButton: UIButton = {
        let bt = UIButton(type: .custom)
        bt.backgroundColor = .clear
        bt.addTarget(self, action: #selector(handleClearButton(button:)), for: .touchUpInside)
        return bt
    }()

    weak var delegate: HeaderCellDelegate?

   //MARK: - Init
   required init?(coder aDecoder: NSCoder) {
        return nil
    }

    override init(frame: CGRect) {
        super.init(frame: frame)
        configureCell()
        addViews()
        setConstraints()
    }

....

    //MARK: - Handlers
    @objc func handleClearButton(button: UIButton) {
        delegate?.expandSelectedHeader(self)
    }

Protocol: HeaderCellDelegate

protocol HeaderCellDelegate: class {
    func expandSelectedHeader(_ header: UICollectionViewCell)
}

Controller: SomeController

func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
        switch kind {
        case UICollectionView.elementKindSectionHeader:
            let header = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: reuseIdentifierForHeader, for: indexPath) as! HeaderCell
            header.toMenuControllerDelegate = self
            return header

        case UICollectionView.elementKindSectionFooter:
            let footer = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: reuseIdentifierForFooter, for: indexPath) as! MenuFooterCell
            return footer
        default:
            return UICollectionReusableView()
        }
    }


extension SomeController:HeaderCellDelegate {
    func expandSelectedHeader(_ header: UICollectionViewCell) {
        let indexPath = collectionView.indexPath(for: header)
        print(indexPath)
    }
}

I am trying to using the clearButton inside headerView that when the button is tapped it will send itself(UIcollectionViewCell) to the controller. So once the controller receives information about the cell, I can use collectionView.indexPath(for cell:UICollectionViewCell) to get the indexPath of header in which the button is tapped. But with the code above, I am only getting nil for print(indexPath).

How can I go about the problem??? I appreciate your help in advance.

Upvotes: 0

Views: 882

Answers (2)

Jawad Ali
Jawad Ali

Reputation: 14397

Instead of sending whole cell and then get index path. Send IndexPath in protocol and get header from that is a good approach

override func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
  switch kind {
    case UICollectionElementKindSectionHeader:
        let headerView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "header", for: indexPath) as! HeaderCollectionReusableView
        let gestureRecognizer: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(didSelectSection(gesture:)))
        headerView.addGestureRecognizer(gestureRecognizer)
        return headerView
    }
}

Now in didSelectSection :

@objc func didSelectSection(_ gestureRecognizer: UITapGestureRecognizer) {
    let indexPaths = self.collectionView?.indexPathsForVisibleSupplementaryElements(ofKind: UICollectionElementKindSectionHeader)
    for indexPath in indexPaths! {
        if (gestureRecognizer.view as! HeaderCollectionReusableView) == collectionView?.supplementaryView(forElementKind: UICollectionElementKindSectionHeader, at: indexPath){
            print("found at : \(indexPath)")
            break
        }
    }
}

Upvotes: 0

Maysam
Maysam

Reputation: 7367

Your delegate function, expandSelectedHeader() does not know about its indexPath unless you pass it to. A workaround is you declare a index path property within your HeaderCell class and pass the value when you are creating the supplementary view:

class HeaderCell: UICollectionViewCell {
    //MARK: - Properties
    var indexPath: IndexPath?
   // rest of the code
}

//MARK: - Handlers
    @objc func handleClearButton(button: UIButton) {
        delegate?.expandSelectedHeader(self, indexPath: self.indexPath)
    }

Also change the protocol a bit:

protocol HeaderCellDelegate: class {
    func expandSelectedHeader(_ header: UICollectionViewCell, indexPath: IndexPath?)
}

When you are creating the view assign the index path:

// ...
let header = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: reuseIdentifierForHeader, for: indexPath) as! HeaderCell
// I'd suggest do not force down case the view as HeaderCell, use if..let
header.toMenuControllerDelegate = self
header.indexPath = indexPath
// ...

Finally:

extension SomeController:HeaderCellDelegate {
    func expandSelectedHeader(_ header: UICollectionViewCell, indexPath: IndexPath) {
        print(indexPath)
    }
}

Upvotes: 1

Related Questions