从不同于 Cell Click 的 UICollectionViewCell 按钮执行 Segue

Posted

技术标签:

【中文标题】从不同于 Cell Click 的 UICollectionViewCell 按钮执行 Segue【英文标题】:Perform Segue from UICollectionViewCell Button different from Cell Click 【发布时间】:2017-04-17 18:37:09 【问题描述】:

我有一个UICollectionViewCell,还有一个UIButton。我有两个不同的动作。第一个,当用户按下单元格时,会用didSelectITemAt切换到另一个视图;第二个,当用户在单元格内按下UIButton。 我的问题是,在MyCollectionViewCell 的 Swift 代码上,我无法执行 segue,当我编写代码时:

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

它说错误:

MyCollectionViewCell 类型的值没有成员 performSegue。

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

我如何从一个单元格创建一个与单击单元格本身不同的转场?

【问题讨论】:

您考虑过使用委托吗? 所以您试图从单元格以及单元格内的按钮中分离?哪个不工作? 两个我都想要,我想让他们去不同的地方。 【参考方案1】:

你不能从你的UICollectionViewCell 子类中调用performSegue,因为UICollectionViewCell 上有no interface declared 这样。

它之所以工作didSelectItemAtIndexPath() 是因为我认为你的UICollectionView 的delegate 是一个UIViewController 子类,它具有称为performSegueWithIdentifier:()` 的函数。

当您的UICollectionViewCell 中的按钮被点击时,您需要通知您的UIViewController,因为您有各种可能性,例如 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)
    

【讨论】:

谢谢,我关心女巫牢房被窃听了,我该怎么办? 谢谢,马上试试!【参考方案2】:

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

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

Swift 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
    

您也可以将此方法与表视图控制器一起使用。

【讨论】:

【参考方案3】:

另一个也很有效的解决方案:

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)
     

【讨论】:

以上是关于从不同于 Cell Click 的 UICollectionViewCell 按钮执行 Segue的主要内容,如果未能解决你的问题,请参考以下文章

如何在 BitLocker 解密驱动器上从不同于 Windows 的操作系统中检索添加的文件

Eclipse J-Link ATMEL ARM ATSAME70Q21。当代码从不同于 0x00400000 的地址开始时进行调试

this.$set,或者Vue.set(),@cell-click=“cellClick“

外包项目大体思路

Objective C - cellForRowAtIndexPath 单元格从不为零?

如何从不同来源的 Chrome 扩展程序提供文件?