'How can I have onclick functionality for my CollectionView cells?

I want to make it so that when I tap on a CollectionView Cell, it segues to another view. I also want to pass a user ID to this view so I can query the database. This is what I have implemented so far:

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


        let cell = collectionview.dequeueReusableCell(withReuseIdentifier: "userCell", for: indexPath) as! UserCell

        print(user[indexPath.row].imagePath!)


        cell.userImage.sd_setImage(with: URL(string: user[indexPath.row].imagePath!))

        cell.nameLabel.text = user[indexPath.row].username
        cell.userID = user[indexPath.row].userID

        let destinationVC = ProfileViewController()
        destinationVC.sentUserID = user[indexPath.row].userID!

        // Let's assume that the segue name is called playerSegue
        // This will perform the segue and pre-load the variable for you to use
        //destinationVC.performSegue(withIdentifier: "toProfileFromSearch", sender: self)


        cell.addButtonTapAction = {
            // implement your logic here, e.g. call preformSegue()
            self.performSegue(withIdentifier: "toProfileFromSearch", sender: self)
        }
        //cell.userImage.downloadImage(from: self.user[indexPath.row].imagePath!)
        //checkFollowing(indexPath: indexPath)


        return cell
    }

This is in the individual creation of each cell. When I click the user profile in the search area, nothing happens.

I followed other stack overflow questions to get this far. Can anyone make a complete solution for other people that need this too?



Solution 1:[1]

You can use the didSelectItemAt function, check this

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
    let VC1 = self.storyboard!.instantiateViewController(withIdentifier: "IDYOURVIEW") as! ProfileViewController
    VC1.sentUserID = user[indexPath.row].userID!
    self.navigationController?.pushViewController(VC1, animated: true)
}

If you're using segues

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
    self.performSegue(withIdentifier: "toProfileFromSearch", sender: user[indexPath.row].userID!)
}

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {

    if segue.identifier == "toProfileFromSearch"
    {
      let vc = segue.destination as? ProfileViewController
      if let id = sender as! String
      {
          vc?.sentUserID = id
      }
    }
}

Solution 2:[2]

There is another better way to handle this using protocol

protocol UserCellTapedDelegate: AnyObject {
    func didTapButton(_ cell: UserCell, didSelectItemAt id: Int)
}

then your cell would be like:

class UserCell: UICollectionViewCell {
    public var userID: Int!
    public weak var delegate: UserCellTapedDelegate?
    
    @objc private func addButtonTapAction() {
        delegate?.didTapButton(self, didSelectItemAt: userID)
    }
}

userID: to store the user ID.

delegate: use an optional weak (in terms of memory management) delegate reference in your cell.

addButtonTapAction func to handle target of the button/or tap gesture on Any UIView.


The next step is to go back to your UIViewController and conform to the custom delegate:

extension ViewController: UserCellTapedDelegate  {
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionview.dequeueReusableCell(withReuseIdentifier: "userCell", for: indexPath) as! UserCell
        ...

        cell.userID = user[indexPath.row].userID!
        cell.delegate = self

        return cell
     }

    func didTapButton(_ cell: UserCell, didSelectItemAt id: Int) {
        self.performSegue(withIdentifier: "toProfileFromSearch", sender: id)
    }
    
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "toProfileFromSearch" {
            let vc = segue.destination as! ProfileViewController
            if let id = sender as! String {
                vc.sentUserID = id
            }
        }
    }
}

Hope this helps you ?

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 creeperspeak
Solution 2 Alirza Eram