0

I have created a View Controller that contains a UITableView and each UITableViewCell contains a UICollectionView.

I made 2 API calls and every collectionView present the first 5 results of each API call.

Also, I added a button on each TableView Header on the right corner with the title "Show All". You can see the screen on the Image below.

Here is how I add the tableView header button:

func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
    let headerView = UIView(frame: CGRect(x: 0, y: 0, width: tableView.frame.width, height: 100))

    let showHideButton: UIButton = UIButton(frame: CGRect(x:headerView.frame.size.width - 80, y:0, width:75, height:35))
    showHideButton.setTitle("Show All", for: .normal)
    showHideButton.titleLabel?.font = UIFont.boldSystemFont(ofSize: 18)
    showHideButton.setTitleColor(#colorLiteral(red: 0.9607843137, green: 0.007843137255, blue: 0.03137254902, alpha: 1), for: .normal)
    //showHideButton.addTarget(self, action: #selector(btnShowHideTapped), for: .touchUpInside)

    headerView.addSubview(showHideButton)

    return headerView
}

When I tap on "show all" button on tableView header, I want to jump to another view controller ("showAllViewController") and represent all the result of my object and when I tap on the Image of CollectionViewCell I want to jump to another view controller ("detailsViewController"). How can I do it using delegates and protocols?

Here is an example image with my screen:

enter image description here

Edit: I followed the following steps from this question (navigate on click of collectionview cell inside tableview) but I don't know what I need to write on the "cellTapped()" function:

ViewController.swift :

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as! CategoryRow
        cell.delegate = self
        return cell
    }

MyCell.swift :

protocol CategoryRowDelegate:class {
func cellTapped()
}

CategoryRow.swift :

class CategoryRow : UITableViewCell {
     weak var delegate:CategoryRowDelegate?
    @IBOutlet weak var collectionView: UICollectionView!
}

 func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if delegate!= nil {
delegate?.cellTapped()
}
}

Add the delegate function inside ViewController

func cellTapped(){
//code for navigation
//I don't know what to write
}

Can anybody help me?

Alex Giatrakis
  • 365
  • 3
  • 16
  • I don't think you need delegate to do this, You can directly show a view controller on cell tapped or on button action event – Prashant Tukadiya Aug 23 '19 at 13:34
  • Use the //showHideButton.addTarget(self, action:#selector(btnShowHideTapped),for: .touchUpInside). Then in the btnShowHideTapped() use a segue (or another of the many methods) to go to the next viewcontroller. Then in the prepareForSegue you can send some information to the next viewcontroller if you desire. – AchidF Aug 23 '19 at 14:25
  • This line of code is a copy-paste from the web. What do I need to put in the selector property? – Alex Giatrakis Aug 23 '19 at 14:35
  • You put the name of the function which handels the tap in the selector part. Here is a example: addTarget(self, action: #selector(NameOfFunctionWhichHandles), for: UIControl.Event.touchUpInside) – AchidF Aug 23 '19 at 14:40
  • What is supposed to contain the function which handles the tap? – Alex Giatrakis Aug 23 '19 at 14:43

2 Answers2

1

First of all I would advise you to insert a tag to the button when you create it, so you know which button in the collection the user clicked on, then add:

showHideButton.tag = section // assign the section number to the tag of the button

then, as you already wrote in the code, you assign an action to the button click:

showHideButton.addTarget(self, action: #selector(self.btnShowHideTapped(sender:)), for: .touchUpInside)

so you're gonna get something like that eventually:

showHideButton.setTitle("Show All", for: .normal)
showHideButton.titleLabel?.font = UIFont.boldSystemFont(ofSize: 18)
showHideButton.setTitleColor(#colorLiteral(red: 0.9607843137, green: 0.007843137255, blue: 0.03137254902, alpha: 1), for: .normal)
showHideButton.tag = section // section Number for Header
showHideButton.addTarget(self, action: #selector(self.btnShowHideTapped(sender:)), for: .touchUpInside) // Sender UIButton

And in your function you call back to click =>

@objc func btnShowHideTapped(sender: UIButton) {
   print(sender.tag)
   // Switch Action if is HeaderView 0 or HeaderView 1 etc...
   // self.present(YourViewController...) OR self.performSegue(withIdentifier: "detailsViewController", sender: nil)
}

I hope I've been there for you. Let me know.

mfiore
  • 321
  • 3
  • 16
  • Thank you! But I want to present a view Controller with the current collection view data. Not the same static view controller every time. I supposed that with some way I need to override the prepare function. Right? – Alex Giatrakis Aug 23 '19 at 15:15
  • Can you tell me how I can jump to another view controller when I tap on the cell? This is more important for me right now. Thanks! – Alex Giatrakis Aug 26 '19 at 09:11
  • 1
    I answered you, just make or a present or invoke a following... depends how you want to move to the next viewcontroller... Look at the example I wrote to you... – mfiore Aug 27 '19 at 10:10
  • 1
    you can also look here: https://stackoverflow.com/questions/24099533/swift-presentviewcontroller or https://developer.apple.com/documentation/uikit/uiviewcontroller/1621380-present it all depends on how you want to present your viewController – mfiore Aug 27 '19 at 10:12
  • Ok, thanks! That works fine for the "show All" button. What about when I tap on a collectionView cell? – Alex Giatrakis Aug 29 '19 at 11:46
  • Ah, that depends on what you want to do... alone nothing happens XD – mfiore Aug 29 '19 at 14:50
0
1] In separate dataSource method - create protocol
    
    protocol myProductsDelegate: class {
        
        func cellTaped()
       
    }
    class ProductsDataSource: NSObject, UICollectionViewDataSource {
    
        var delegate: myProductsDelegate?
        
    //    func collectionView(_ collectionView: UICollectionView, //numberOfItemsInSection section: Int) -> Int
     //   {
    //        return 
    //    }
        
        func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
            
            let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! ProductsCollectionViewCell
            
           
            return cell
            }
    
 2] In separate delegate method -

class ProductsDelegate: NSObject, UICollectionViewDelegate {
    
    var delegate: myProductsDelegate?
    
        func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
            if delegate != nil {
                delegate?.cellTaped()
            }
        }
    
    3] Note: In viewDidload - 
    
            self.CollectionView.delegate = self.myDelegate
            self.CollectionView.dataSource = self.myDataSource
            self.myDelegate.delegate = self
    
    4] In your main view controller where collectionView is available - 

    var myDelegate: ProductsDelegate = ProductsDelegate()
    var myDataSource: ProductsDataSource = ProductsDataSource()
    
     extension MainViewController: ProductsDelegate {
    
        func cellTaped() 
    {
            let vc = storyboard?.instantiateViewController(identifier: "SecondViewController") as? SecondViewController
            self.present(vc!, animated: true, completion: nil)
        }