Clint
Clint

Reputation: 387

How to grab indexPath item from a collection view cell for a delegate?

I have a collectionView that has a section header. In that section header I've added another collectionView that displays recommended profiles for users to follow, and it scrolls horizontal.

I cannot push view controllers from a ReuseableView ( that holds the second collection view), so I created a protocol that will hold a function that can push the view controller for me.

When I tap a profile (cell) it pushes me to my own profile. Because I cannot grab the indexPath.item that is in another collectionView.

Protocol

protocol PeopleToFollowDelegate {
    func handleProfileTapped(for cell: FeedReusableView)
}

Function to push user

 // Create function to push users to the correct profile when selected
    func handleProfileTapped(for header: FeedReusableView) {

        print("profile tapped, push user to the correct profile page")
       let header = FeedReusableView()

        //try to grab the indexpath item so the corrext data is pushed
        let user = header.peopleToFollow // ??? What goes here? I cannot grab index path

            let storyBoard : UIStoryboard = UIStoryboard(name: "Main", bundle:nil)

           let profileViewController = storyBoard.instantiateViewController(withIdentifier: "profileViewController") as? ProfileViewController
            profileViewController?.user? = user


            self.navigationController?.pushViewController(profileViewController!, animated: true)

       }
// When profile is tapped, push user to userProfile
    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {

        let user = peopleToFollow[indexPath.item]
        let storyBoard : UIStoryboard = UIStoryboard(name: "Main", bundle:nil)
        let profileViewController = storyBoard.instantiateViewController(withIdentifier: "profileViewController") as? ProfileViewController


        profileViewController?.user = user

        // Then push to next controller ( profile)


    }

To sum it up, I just need a way to grab the indexPath.item somehow for that func.

Edit

Here is also were I use the function in the FeedReuseableView

var delegate: PeopleToFollowDelegate?


func numberOfSections(in collectionView: UICollectionView) -> Int {
        return 1
    }

    // Return the number of profiles
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return peopleToFollow.count
    }

    //Display the recommended profiles
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "profilesCell", for: indexPath) as! PeopleToFollowCollectionCell

        cell.user = peopleToFollow[indexPath.item]

        return cell
    }

    // When profile is tapped, push user to userProfile
    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {

        profilesTapped()

    }

    @objc func profilesTapped() {
        delegate?.handleProfileTapped(for: self)

      }


Upvotes: 1

Views: 958

Answers (3)

Shehzad Ali
Shehzad Ali

Reputation: 1845

you can change the implementation of didSelectRow from

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {

        profilesTapped()
}

to

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {

        profilesTapped(user: peopleToFollow[indexPath.item])
}

Here is the implementation of profilesTapped

@objc func profilesTapped(user: User) {
    delegate?.handleProfileTapped(for: user)
}

Edited: For pushing view controller you should do this. Apologies if I typed something wrong as I am using my phone now.

func handleProfileTapped(for user: User) {
    let storyBoard : UIStoryboard = UIStoryboard(name: "Main", bundle:nil)

    if let profileViewController = storyBoard.instantiateViewController(withIdentifier: "profileViewController") as? ProfileViewController {
    profileViewController.user = user
    self.navigationController?.pushViewController(profileViewController, animated: true)

}

Upvotes: 3

Akshay Jadhav
Akshay Jadhav

Reputation: 145

As suggested by @Abu Ul Hassan you can pass IndexPath as a argument to your protocol function but after reviewing your code I observed that only thing you need is selected index therefore for simplicity you can do this in following way:

  1. Modify your protocol method

     protocol PeopleToFollowDelegate {
         func handleProfileTapped(forIndex selectedIndex: Int)
     }
    
  2. Call delegate function from User's collectionView's didSelect delegate

     func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
          peopleToFollowDelegate.handleProfileTapped(forIndex: indexPath.item) 
    
     }
    
  3. Then write handleProfileTapped function like this:

    func handleProfileTapped(forIndex selectedIndex: Int) {
    
         let user = peopleToFollow[selectedIndex]
         let storyBoard : UIStoryboard = UIStoryboard(name: "Main", bundle:nil)
         let profileViewController = storyBoard.instantiateViewController(withIdentifier:"profileViewController") as? ProfileViewController
    
    
         profileViewController?.user = user
    
         // Then push to next controller
    }
    

Upvotes: 1

Sand'sHell811
Sand'sHell811

Reputation: 388

You can use collection view delegate didSelectItem inside section header and directly push to profile viewcontroller from section reusable view by accessing topMost viewcontroller in navigation stack by using following code.

extension UIApplication {
 class func topVC(controller: UIViewController? = UIApplication.shared.keyWindow?.rootViewController) -> UIViewController? {
    if let navigationController = controller as? UINavigationController {
      return topVC(controller: navigationController.visibleViewController)
    }
    if let tabController = controller as? UITabBarController {
      if let selected = tabController.selectedViewController {
        return topVC(controller: selected)
      }
    }
    if let presented = controller?.presentedViewController {
      return topVC(controller: presented)
    }
    return controller
  }
}

extension UIViewController {
  func pushVC(_ vc: UIViewController, animated: Bool = true) {
    navigationController?.pushViewController(vc, animated: animated)
  }
}

Use case: UIApplication.topVC()?.pushVC(, animated: true)

Upvotes: 0

Related Questions