Archie Gertsman
Archie Gertsman

Reputation: 1661

Swift add button to UICollectionViewCell that opens new controller

I have a UICollectionViewCell header on a UICollectionViewController, and I've added a button to it. I would like for the button, when clicked, to push a new view controller atop the current one. The problem is that the button doesn't have access to the navigation controller of the UICollectionViewController, so I there's no way to directly push a controller from, say, a connector to the buttn (that I know of). Is there any way to achieve this? Maybe something can be overriden, such as a collectionView function. Thanks!

Upvotes: 2

Views: 2146

Answers (1)

Kirill  Dubovitskiy
Kirill Dubovitskiy

Reputation: 306

If you just want to process the cell selection there is a handy method in the UICollectionViewDelegate that you can implement to get the index path of the pressed cell.

If your goal is to have a custom button inside the cell (or maybe even several) you can use delegation pattern to retrieve user actions to your controller to than process in any way, including pushing/presenting new controllers. Assign the controller's instance (the one managing the collection view) to the delegate member of your cell.

  1. Define a protocol that I would call something like MyCustomCellDelegate (replace MyCustomCell with a more appropriate name for your case). Something like MyCustomCellDelegate: class { func didPressButtonX() }
  2. Declare an optional delegate property in your cell subclass. weak var delegate: MyCustomCellDelegate?
  3. Implement your delegate protocol by the class you want to respond to button presses (or any other interactions defined by your protocol).
  4. Every time you create/dequeue a cell for your UICollectionView to use you set the delegate property to the view controller managing the collection view. cell.delegate = self (if done inside the view controller itself).
  5. After receiving the UI event inside your custom cell use your delegate property to retrieve the action to the controller (or with ever object you used when assigning the property). Something like: delegate?.didPressButtonX()
  6. In your class that implements MyCustomCellDelegate use the method to push the new controller.

Below I will provide sample code that should give more details on the implementation of the proposed solution:

// In your UICollectionViewCell subclass file

protocol MyCustomCellDelegate: class {
    func didPressButtonX()
    func didPressButtonY()
}

MyCustomCell: UICollectionViewCell {
    weak var delegate: MyCustomCellDelegate?

    @IBOutlet var buttonX: UIButton!
    @IBOutlet var buttonY: UIButton!

    @IBAction func didPressButtonX(sender: Any) {
        delegate?.didPressButtonX()
    }

    @IBAction func didPressButtonY(sender: Any) {
        delegate?.didPressButtonY()
    }
}

// Now in your UICollectionViewController subclass file

MyCustomCollectionViewController: UICollectionViewController {
    // ...

    override func collectionView(UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier identifier: "YourCellIdentifierGoesHere", for indexPath: indexPath) as! MyCustomCell
        // In here we assign the delegate member of the cell to make sure once
        // an UI event occurs the cell will call methods implemented by our controller
        cell.delegate = self

        // further cell setup if needed ...

        return cell
    }
}

// In order for the instance of our controller to be used as cell's delegate 
// we implement the protocol that we defined earlier in the cell file 
extension MyCustomCollectionViewController: MyCustomCellDelegate {
    func didPressButtonX() {
        print("X button was pressed")

        // now lets finally push some new controller
        let yourNextCoolViewController = UIViewController()
        self.push(yourNextCoolViewController, animated: true)

        // OR if you are using segues
        self.performSegue(withIdentifier: "YourSegueIdentifierGoesHere", sender: self)
    }

    func didPressButtonY() {
        print("Y button was pressed")
    }
}

Upvotes: 2

Related Questions