如何从位于集合视图单元格内的步进器中获取选定的 IndexPath?

Posted

技术标签:

【中文标题】如何从位于集合视图单元格内的步进器中获取选定的 IndexPath?【英文标题】:How to get selected IndexPath from a stepper located inside a collection view cell? 【发布时间】:2018-12-12 06:44:37 【问题描述】:

我有一个集合视图,它在集合视图单元格内有步进器,用于增加产品的数量,如下图所示。

我需要知道,当我单击集合视图单元格上的步进器时。我怎么知道那个集合视图单元格的indexPath.item?所以我可以使用视图控制器中选择的 indexPath 修改数据?

所以如果我在第二个单元格中更改步进器,我将始终得到 indexPath.item = 1

我之前认为indexPath 将来自下面的didSelectItemAt 方法。但是当我点击集合视图单元格内的步进器时,似乎不会触发didSelectItemAt 方法。

  func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) 

    

所以我想我可以从cellForRowAt IndexPath 获取 indexPath 并使用协议委托模式。这是我做的方法,我得到了错误的indexPath

所以如果我在第二个单元格中更改步进器,我不会总是得到 indexPath.item = 1 ,它可以是 2,3,0 等。

这是视图控制器代码:

class WishListVC: UIViewController, ListProductCellDelegate 

    var products = [Product]()
    var selectedProduct : Product?

     // method from ListProductCellDelegate
    func stepperButtonDidTapped(at selectedIndexPath: IndexPath, stepperValue: Int) 

        // get selectedIndexPath
        // perform some action based on selectedIndexPath

    


extension WishListVC : UICollectionViewDataSource, UICollectionViewDelegate 

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int 
        return products.count
    

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell 

        guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: WishListStoryboardData.CollectionViewIdentifiers.productSliderCell.rawValue, for: indexPath) as? ListProductCell else  return UICollectionViewCell()


        cell.productData = products[indexPath.item]
        cell.indexPath = indexPath // I send the indexPath to the cell.
        cell.delegate = self

        return cell
    

    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) 

        selectedProduct = products[indexPath.item]
        performSegue(withIdentifier: WishListStoryboardData.SegueIdentifiers.toProductVC.rawValue, sender: nil)
    



这里是集合视图单元格中的代码:

protocol ListProductCellDelegate 
    func stepperButtonDidTapped( at selectedIndexPath: IndexPath, stepperValue: Int)


class ListProductCell: UICollectionViewCell 

    var indexPath: IndexPath?
    var delegate: ListProductCellDelegate?

    var productData : Product? 
        didSet 
            updateUI()
        
    

    @IBAction func stepperDidTapped(_ sender: GMStepper) 
        guard let indexPath = indexPath, let collectionView = collectionView else return
        self.delegate?.stepperButtonDidTapped(at: indexPath, stepperValue: Int(sender.value))
    


    func updateUI() 
        // update the UI in cell.
    

【问题讨论】:

只要加上stepper tag value = indexPath.row,在stepper tag value的基础上检查即可。 【参考方案1】:

您可以尝试将tag 属性添加到步进器。因此,当您单击步进器时,您可以聆听其选择器并确定调用了哪个步进器。标记值应与项目索引相同。

类似的东西

cell.stepper.tag = indexPath.row

上面的代码应该放在 cellForRowAt 委托函数中。

然后当用户点击步进器时调用一个函数并检查标签值

类似的东西

func stepperClicked(sender) 
    //check sender.tag value
    //Do something here with the tag value

【讨论】:

如果我单击一个单元格,似乎 indexPath.row 仍然会给出随机 int 值 你能解释一下随机值是什么意思吗?【参考方案2】:

在 Swift 中,回调闭包可能是最有效的解决方案。它独立于索引路径、标签、视图层次结构数学和协议。

在单元格中添加一个传递步进器实例的callback 属性。删除indexPathdelegate。根本不需要协议。

IBAction 调用callback 并传递步进器实例

class ListProductCell: UICollectionViewCell 

    var callback: ((GMStepper) -> Void)?

    var productData : Product? 
        didSet 
            updateUI()
        
    

    @IBAction func stepperDidTapped(_ sender: GMStepper) 
        callback?(sender)
    


    func updateUI() 
        // update the UI in cell.
    

cellForItemAt 的控制器中设置闭包并处理回调。索引路径在方法中被捕获。

不要guard 单元格。强行拆开它。代码不得崩溃。如果确实如此,则表明 设计 错误。使用guard 方式,表格视图将不显示任何内容,您也不知道为什么。

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell 

    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: WishListStoryboardData.CollectionViewIdentifiers.productSliderCell.rawValue, for: indexPath) as! ListProductCell
    cell.productData = products[indexPath.item]
    cell.callback =  stepper in 
       // handle the callback
    
    return cell

【讨论】:

这是我能找到的最好的解决方案,而且奏效了!【参考方案3】:

您拥有步进器,因为它是您的操作方法中的sender。步进器有一个超级视图,它是单元格(您可能必须走上多个超级视图才能到达单元格)。获得单元格后,您可以调用indexPath(for:) 来获取索引路径。完毕。

https://developer.apple.com/documentation/uikit/uicollectionview/1618094-indexpath

【讨论】:

以上是关于如何从位于集合视图单元格内的步进器中获取选定的 IndexPath?的主要内容,如果未能解决你的问题,请参考以下文章

一次从所有集合视图单元格内的文本视图中获取文本

如何在表格视图单元格内创建集合视图

从选定的集合视图单元中获取信息

表视图单元格内的集合视图

如何从集合视图中删除多个选定的单元格? (迅速)

将数据从集合视图单元格内的表视图单元格传输到另一个集合视图单元格 [带图片!]