从UICollectionViewCell按钮执行Segue,与Cell Click不同

时间:2017-04-17 18:37:10

标签: ios swift swift3 uicollectionviewcell

我有UICollectionViewCellUIButton。我有两种不同的行为。第一个,当用户按下单元格时,它将转到didSelectITemAt的另一个视图;第二个,当用户按下单元格内的UIButton时 我的问题是,在MyCollectionViewCell的Swift代码中,当我编写代码时,我无法执行segue:

self.performSegue(withIdentifier: "toStoreFromMyDiscounts", sender: nil)

它说错误:

  

MyCollectionViewCell类型的值没有成员performSegue。

我也写不出prepareForSegue,它不会自动完成。

如何从单元格创建segue,这与单击单元格本身不同?

3 个答案:

答案 0 :(得分:10)

您无法从performSegue子类中致电UICollectionViewCell,因为UICollectionViewCell上的no interface declared就是这样。

它工作didSelectItemAtIndexPath()的原因是因为我认为UICollectionView的{​​{3}}是UIViewController子类,具有名为delegate的函数

您需要在UIViewController中点击按钮时通知您的UICollectionViewCell,以获得各种可能性,例如KVO或使用代表。

这是一个小代码片段,如何使用KVO。这个解决方案很棒,只要你不在乎,按下按钮的是哪个单元格。

import UIKit

class CollectionViewCell: UICollectionViewCell {
    @IBOutlet weak var button: UIButton!
}

class CollectionViewController: UIViewController {
    @IBOutlet weak var collectionView: UICollectionView!
}

extension CollectionViewController: UICollectionViewDataSource {

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

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) ->  UICollectionViewCell {
        let cell: CollectionViewCell = self.collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! CollectionViewCell
        // Add your `UIViewController` subclass, `CollectionViewController`, as the target of the button
        // Check out the documentation of addTarget(:) https://developer.apple.com/reference/uikit/uicontrol/1618259-addtarget
        cell.button.addTarget(self, action: #selector(buttonTappedInCollectionViewCell), for: .touchUpInside)
        return cell
    }

    func buttonTappedInCollectionViewCell(sender: UIButton) {
        self.performSegue(withIdentifier: "toStoreFromMyDiscounts", sender: nil)
    }
}

修改 如果您关心触摸事件发生在哪个单元格中,请使用委托模式。

import UIKit

protocol CollectionViewCellDelegate: class {
    // Declare a delegate function holding a reference to `UICollectionViewCell` instance
    func collectionViewCell(_ cell: UICollectionViewCell, buttonTapped: UIButton)
}

class CollectionViewCell: UICollectionViewCell {
    @IBOutlet weak var button: UIButton!
    // Add a delegate property to your UICollectionViewCell subclass
    weak var delegate: CollectionViewCellDelegate?

    @IBAction func buttonTapped(sender: UIButton) {
        // Add the resposibility of detecting the button touch to the cell, and call the delegate when it is tapped adding `self` as the `UICollectionViewCell`
        self.delegate?.collectionViewCell(self, buttonTapped: button)
    }
}

class CollectionViewController: UIViewController {
    @IBOutlet weak var collectionView: UICollectionView!
}

extension CollectionViewController: UICollectionViewDataSource {

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

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) ->  UICollectionViewCell {
        let cell: CollectionViewCell = self.collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! CollectionViewCell
        // Asssign the delegate to the viewController
        cell.delegate = self
        return cell
    }
}

// Make `CollectionViewController` confrom to the delegate 
extension CollectionViewController: CollectionViewCellDelegate {
    func collectionViewCell(_ cell: UICollectionViewCell, buttonTapped: UIButton) {
        // You have the cell where the touch event happend, you can get the indexPath like the below 
        let indexPath = self.collectionView.indexPath(for: cell)
        // Call `performSegue`
        self.performSegue(withIdentifier: "toStoreFromMyDiscounts", sender: nil)
    }
}

答案 1 :(得分:0)

另一种解决方案也像魅力一样:

extension YOURViewController : UICollectionViewDataSource
{
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
    {
         let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "YOURCell", for: indexPath) as! YOURCollectionViewCell

         cell.butTapped = {
             [weak self] (YOURCollectionViewCell) -> Void in
             // do your actions when button tapped
         }
    }        
    return cell
}


class YOURCollectionViewCell: UICollectionViewCell
{
     var butQRTapped: ((YOURCollectionViewCell) -> Void)?
     @IBAction func deleteButtonTapped(_ sender: AnyObject) {
         butTapped?(self)
     }
}

答案 2 :(得分:0)

这是一个优雅的解决方案,只需要几行代码:

  1. 创建自定义UICollectionViewCell子类
  2. 使用情节提要,为按钮的“ Touch Up Inside ”事件定义IBAction
  3. 定义闭包
  4. 从IBAction调用闭包

快速4 + 代码

class MyCustomCell: UICollectionViewCell {

        static let reuseIdentifier = "MyCustomCell"

        @IBAction func onAddToCartPressed(_ sender: Any) {
            addButtonTapAction?()
        }

        var addButtonTapAction : (()->())?
    }

下一步,在

的闭包内部实现要执行的逻辑
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: MyCustomCell.reuseIdentifier, for: indexPath) as? MyCustomCell else {
            fatalError("Unexpected Index Path")
        }

        // Configure the cell
        // ...


        cell.addButtonTapAction = {
            // implement your logic here, e.g. call preformSegue()  
            self.performSegue(withIdentifier: "your segue", sender: self)              
        }

        return cell
    }

您也可以将这种方法用于表视图控制器。