0

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 ??

Developer Omari
  • 434
  • 5
  • 14

1 Answers1

5

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);
    }
}
  • 1
    Although Mehmet's approach works, I don't think you should ever have navigation logic in your cell, you really want to pass the HomeController enough information so that it can perform the correct business logic (in this case navigation logic). I would make my delegate speak in terms of what happened and not what to do: the delegate method would look more like `homeCellDidTapUserSearch()`. You can even use swift's awesome enums so you have `homeCellDidTap(.userSearch)`. Later you can use these enums to even configure the home cell so that you're not re-inventing the wheel every time. – Jacob Jan 06 '19 at 01:09
  • Thanks it worked and I can push a new ViewController. Imagine I click on cell number 3 and instead of pushing a new ViewController I want to change the content of cell number 2. how is this possible ? – Developer Omari Jan 06 '19 at 12:09