Perform Segue from UICollectionViewCell Button different from Cell Click

前端 未结 3 964
旧时难觅i
旧时难觅i 2021-02-06 15:27

I have a UICollectionViewCell, with a UIButton. And I have two different actions. The first one, when the user presses the cell, it will segue to anoth

相关标签:
3条回答
  • 2021-02-06 15:55

    Here's an elegant solution that only requires a few lines of code:

    1. Create a custom UICollectionViewCell subclass
    2. Using storyboards, define an IBAction for the "Touch Up Inside" event of your button
    3. Define a closure
    4. Call the closure from the IBAction

    Swift 4+ code

    class MyCustomCell: UICollectionViewCell {
    
            static let reuseIdentifier = "MyCustomCell"
    
            @IBAction func onAddToCartPressed(_ sender: Any) {
                addButtonTapAction?()
            }
    
            var addButtonTapAction : (()->())?
        }
    

    Next, implement the logic you want to execute inside the closure in your

    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
        }
    

    You can use this approach also with table view controllers.

    0 讨论(0)
  • 2021-02-06 16:03

    You can not call performSegue from your UICollectionViewCell subclass, because there is no interface declared on UICollectionViewCell like that.

    The reason why it is working didSelectItemAtIndexPath() is because i suppose the delegate of your UICollectionView is a UIViewController subclass, what has the function called performSegueWithIdentifier:()`.

    You need to notify your UIViewController when the button was clicked in your UICollectionViewCell, for what you have various possibilities, like KVO or using delegate.

    Here is a little code sniplet, how to use KVO. This solution is great, as long as you do not care, in which cell was the button pressed.

    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)
        }
    }
    

    EDIT: If you care, in which cell the touch event has happend, use the delegate pattern.

    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)
        }
    }
    
    0 讨论(0)
  • 2021-02-06 16:14

    Another solution that also works like a charm:

    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)
         }
    }
    
    0 讨论(0)
提交回复
热议问题