如何获取 UICollectionView Header 的 IndexPath?

Posted

技术标签:

【中文标题】如何获取 UICollectionView Header 的 IndexPath?【英文标题】:How to get IndexPath for UICollectionView Header? 【发布时间】:2020-01-02 08:30:14 【问题描述】:

视图:页眉视图

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)
    

协议:HeaderCellDelegate

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

控制器: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)
    

我正在尝试在 headerView 中使用 clearButton,当点击按钮时,它会将自身(UIcollectionViewCell)发送到控制器。因此,一旦控制器接收到有关单元格的信息,我就可以使用collectionView.indexPath(for cell:UICollectionViewCell) 来获取点击按钮的标题的 indexPath。但是使用上面的代码,我只能得到nilprint(indexPath)

我该如何解决这个问题??? 我提前感谢您的帮助。

【问题讨论】:

【参考方案1】:

您的委托函数expandSelectedHeader() 不知道它的indexPath,除非您将它传递给它。一种解决方法是在 HeaderCell 类中声明一个索引路径属性,并在创建补充视图时传递该值:

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)
    

还要稍微修改一下协议:

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

在创建视图时分配索引路径:

// ...
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
// ...

最后:

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

【讨论】:

感谢您对 Maysam 的评论,所以我们不能对标题单元格做这样的事情吗? ***.com/a/44368931/11530917 重点是你的子类本质上并不知道它被分配到的索引路径。 这就是为什么我要在func expandSelectedHeader(_ header: UICollectionViewCell) 中使用let indexPath = collectionView.indexPath(for: header) ?? 我猜它不适用于Supplementary View,但我不确定。【参考方案2】:

而不是发送整个单元格然后获取索引路径。在协议中发送 IndexPath 并从中获取标头是一个好方法

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
    

现在在 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
        
    

【讨论】:

在哪里可以找到 didSelectSection?你是说 didSelectItemAt 吗? gesture.view 这是从哪里来的? 它的gestureRecognizer.view ...抱歉忘记更改 来自参数

以上是关于如何获取 UICollectionView Header 的 IndexPath?的主要内容,如果未能解决你的问题,请参考以下文章

UICollectionView:如何获取部分的标题视图?

如何从子 UICollectionview 中获取 UITableView 的一部分

UICollectionView:如何在委托方法中设置特定项目后获取项目大小

如何在 UICollectionView 中获取选中的 CollectionViewCell?

如何快速获取两个 UICollectionView 的 ScrollView?

如何从选定的 UICollectionView 单元格中获取数据?