iosswiftuinavigationcontrolleruicollectionviewcelluicollectionviewdelegate

How to push a new UICollectionViewController to the navigationController inside a cell of cells of cells


I have build a UICollectionViewController programmatically which returns 4 cells. HomeCell, TrendingCell, SubscriptionCell and AccountCell. All 4 cells should be different and you can scroll them horizontally. <--->.

class HomeController: UICollectionViewController, UICollectionViewDelegateFlowLayout{



    override func viewDidLoad() {
        super.viewDidLoad()
        
         collectionView?.register(HomeCell.self, forCellWithReuseIdentifier: homeCellId)
        collectionView?.register(TrendingCell.self, forCellWithReuseIdentifier: trendingCellId)
        collectionView?.register(SubscriptionCell.self, forCellWithReuseIdentifier: subscriptionCellId)
        collectionView?.register(AccountCell.self, forCellWithReuseIdentifier: accountCellId)
        
        }
        
        
        
 }

Lets take the first cell of the HomeController called HomeCell to illustrate my problem. Homecell has three custom cells called VideoCell, CategoryCell and UserSearchCell.

class HomeCell: UICollectionViewCell, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {

    
    let cellId = "cellId"
    let searchId = "sarchId"
    let scrollId = "scrollId"
    
    
    
    lazy var collectionView: UICollectionView = {
        let layout = UICollectionViewFlowLayout()
        let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
        cv.backgroundColor = UIColor.white
        cv.dataSource = self
        cv.delegate = self
        return cv
    }()
    
    
      override func setupViews() {
        super.setupViews()
  .....

// register  three different cells within HomeCell
        collectionView.register(VideoCell.self, forCellWithReuseIdentifier: cellId)
        collectionView.register(CategoryCell.self, forCellWithReuseIdentifier: scrollId)
        collectionView.register(UserSearchCell.self, forCellWithReuseIdentifier: searchId) //
        
        
    }
    
    
    
        required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}
    

In HomeCell I register the UserSearchCell as third cell.

 func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
       
     
        if indexPath.item == 0 {
            
              cell = collectionView.dequeueReusableCell(withReuseIdentifier: "videoId", for: indexPath)
        } else if indexPath.item == 1{
            
            cell = collectionView.dequeueReusableCell(withReuseIdentifier: categoryId, for: indexPath)
            
        }else {
            
            cell = collectionView.dequeueReusableCell(withReuseIdentifier: searchId, for: indexPath)
           
        }
        
        
        return cell
        
    }

If I click on that element my goal is to push a new ViewController to the navigationController. But I have no access and don't know how to change the view within that nested structure. I tried the didSelectItem method within HomeCell class and was able to print something the console when clicking the third cell but couldn't change the view.

class HomeCell: UICollectionViewCell, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {


func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        if indexPath.item == 2 {
            
        print(123)
        
        }
        
        ....
        
   }

Please help. Is there a way to change the View within the didSelectItem method of HomeCell ??


Solution

  • You need to write a protocol to refer back to your HomeController.

    protocol HomeCellProtocol {
        func pushNavigation(_ vc: UIViewController)
    }
    

    add write delegate property to HomeCell class with

    class HomeCell: ..... {
        var delegate: HomeCellProtocol?
    }
    

    and make HomeController confirm to HomeCellProtocol with

    extention HomeController: HomeCellProtocol {
        func pushNavigation(_ vc: UIViewController) {
            self.navigationController?.pushViewController(vc, animated: true)
        }
    }
    

    and when you setup your HomeCell you need to set your delegate in HomeController

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        cell = collectionView.dequeueReusableCell(withReuseIdentifier: homeCellId, for: indexPath) as HomeCell;
        cell.delegate = self // Set the delegate
        return cell
    }
    

    finally, you can call push function within HomeCell with

    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        if indexPath.item == 2 {
            let vc = UIViewController();
            self.delegate?.pushNavigation(vc);
        }
    }