Fatimah
Fatimah

Reputation: 11

CollectionView Inside TableView

I have a CollectionView in TableViewController cell the tableViewcontains 3 sections each section is a different category. How I can pass different data in each section. Like Netflix app

In UICollectionViewController file

import UIKit
import Alamofire

class HomeViewController: UITableViewController, MovieDataDelegate {

    let tableViewHeaderIdentifier = "FeaturedTableHeader"
    var homePresenter : HomePresenter!


    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.

        let headerNib = UINib(nibName: "FeaturedUITableViewHeaderView", bundle: nil)
        tableView.register(headerNib, forHeaderFooterViewReuseIdentifier: tableViewHeaderIdentifier)

        homePresenter = HomePresenter()
        homePresenter.delegate = self
        homePresenter.fetchData()
        homePresenter.fetchImageData()

    }


    func arrayOfMoviesNames(names: [String]) {
        //print(homePresenter.homeData.moviesNamesArray)
        tableView.reloadData()
    }

    func arrayOfPosters(path: [String]) {
        //print(homePresenter.homeData.posterPathsArray)
    }



    //MARK: - Home UI table
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 1
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell =  tableView.dequeueReusableCell(withIdentifier: "featuredCell", for: indexPath) as! FeaturedTableViewCell

        cell.homeCollectionView.dataSource = self
        return cell
    }

    override func numberOfSections(in tableView: UITableView) -> Int {
        return 3
    }

    override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
        let headerView = tableView.dequeueReusableHeaderFooterView(withIdentifier: tableViewHeaderIdentifier) as! FeaturedUITableViewHeaderView

        switch section {
        case 0:
            headerView.isHidden = true
        case 1:
            headerView.catagoryLabel.text = "Popular Movies"
        case 2:
            headerView.catagoryLabel.text = "Celebs"
        default:
            headerView.catagoryLabel.text = "" as String
        }

        return headerView
    }

    override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {

        if section == 0 {
            return 0
        }
        return 35
    }

    override func tableView(_ tableView: UITableView, estimatedHeightForFooterInSection section: Int) -> CGFloat {
        return 12
    }

    override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {

        guard let tableViewCell = cell as? FeaturedTableViewCell else { return }

        tableViewCell.setCollectionViewDataSourceDelegate(self, forRow: indexPath.row)

    }


}




//MARK: - collectionView
extension HomeViewController : UICollectionViewDataSource, UICollectionViewDelegate {

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return homePresenter.homeData.moviesNamesArray.count
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "homeCollectionCell", for: indexPath) as! HomeCollectionViewCell
        cell.posterImage.image = UIImage(named: "Aladdin")

        cell.movieName.text = "coco"

        return cell
    }


}

In UITableViewCell file

import UIKit

class FeaturedTableViewCell: UITableViewCell {

    @IBOutlet weak var homeCollectionView: UICollectionView!


    override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code
        let collectionNib = UINib(nibName: "HomeCollectionViewCell", bundle: nil)
        homeCollectionView.register(collectionNib, forCellWithReuseIdentifier: "homeCollectionCell")
    }

    override func setSelected(_ selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)

        // Configure the view for the selected state
    }

}
extension FeaturedTableViewCell {

     func setCollectionViewDataSourceDelegate<D: UICollectionViewDataSource & UICollectionViewDelegate>(_ dataSourceDelegate: D, forRow row: Int) {

          homeCollectionView.delegate = dataSourceDelegate
          homeCollectionView.dataSource = dataSourceDelegate
          homeCollectionView.tag = row
          homeCollectionView.reloadData()
}

}


screenshot of app

I want to show diffrent image and text for each section of tabelview

Upvotes: 1

Views: 280

Answers (2)

Andy K
Andy K

Reputation: 7282

Use both UITableView data source and UICollectionView data source methods.

Set 3 sections in UITableView with only one cell for every section.

func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return 1
}

func numberOfSections(in tableView: UITableView) -> Int {
    return 3
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    // Your cell with UICollectionView inside
    let cell = tableView.dequeueReusableCell(withIdentifier: "YOUR_TABLE_VIEW_CELL_IDENTIFIER", for: indexPath)
    // Set UICollectionViewDataSource, also add data source methods in your class, look at next code block
    cell.collectionView.dataSource = self
    return cell
}

// Header for each section, 
func tableView(_ tableView: UITableView, 
titleForHeaderInSection section: Int) -> String? {
    if (section == 0) {
        return nil
    } else if (section == 1) {
        return "Popular movies"
    } else if (section == 2) {
        return "Celebs"
    }
}
// UICollectionViewDataSource methods
override func numberOfSections(in collectionView: UICollectionView) -> Int {
    return 1 // only one section for each UICOllectionView
  }

  override func collectionView(_ collectionView: UICollectionView,
                               numberOfItemsInSection section: Int) -> Int {
    // return here number of items in each UICollectionView
  }

  override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "YOUR_COLLECTION_CELL_IDENTIFIER", for: indexPath)
    // set real data for each UICollectionCell here
    cell.label = "COCO"
    return cell
  }

If you want to

Upvotes: 0

RajeshKumar R
RajeshKumar R

Reputation: 15748

Create a struct Movie and create an array of tuple in the view controller. In tuple add a category title and an array of related movies. In table view data source methods use the main array and in collection view data source methods use the movies array from the corresponding tuple. Set the current tuple/section index as the collectionView tag. And get the appropriate movies array in the collection view data source methods.

//HomeViewController

class HomeViewController: UITableViewController {
    struct Movie {
        var name: String
        var image: UIImage?
        //other details
    }
    var movieDetails:[(title:String, movies:[Movie])] = []
    override func viewDidLoad() {
        super.viewDidLoad()
        tableView.register(FeaturedCell.self, forCellReuseIdentifier: "FeaturedCell")
        movieDetails = [(title: "MoviesDB", movies: [Movie(name: "a", image: UIImage(named: "a")),
                                                     Movie(name: "b", image: UIImage(named: "b")),
                                                     Movie(name: "c", image: UIImage(named: "c"))]),
                        (title: "Popular Movies", movies: [Movie(name: "d", image: UIImage(named: "d")),
                                                           Movie(name: "e", image: UIImage(named: "e")),
                                                           Movie(name: "f", image: UIImage(named: "f"))]),
                        (title: "Celebs", movies: [Movie(name: "g", image: UIImage(named: "g")),
                                                   Movie(name: "h", image: UIImage(named: "h")),
                                                   Movie(name: "i", image: UIImage(named: "i"))])]
    }
    // MARK: - Table view data source
    override func numberOfSections(in tableView: UITableView) -> Int {
        return movieDetails.count
    }
    override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        return movieDetails[section].title
    }
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 1
    }
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "FeaturedCell") as? FeaturedCell ?? FeaturedCell(style: .default, reuseIdentifier: "FeaturedCell")
        cell.collectionView.tag = indexPath.section
        cell.collectionView.delegate = self
        cell.collectionView.dataSource = self
        return cell
    }
}
extension HomeViewController: UICollectionViewDataSource, UICollectionViewDelegate {
    func numberOfSections(in collectionView: UICollectionView) -> Int {
        return 1
    }
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return movieDetails[collectionView.tag].movies.count
    }
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "HomeCell", for: indexPath) as? HomeCell ?? HomeCell()
        let movie = movieDetails[collectionView.tag].movies[indexPath.item]
        cell.posterImage.image = movie.image
        cell.movieName.text = movie.name
        return cell
    }
}

//FeaturedCell

class FeaturedCell: UITableViewCell {

    var collectionView = UICollectionView(frame: .zero, collectionViewLayout: UICollectionViewFlowLayout())

    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        commonInit()
    }
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        commonInit()
    }
    func commonInit() {

        if let layout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout {
            layout.scrollDirection = .horizontal
        }
        collectionView.register(HomeCell.self, forCellWithReuseIdentifier: "HomeCell")
        collectionView.translatesAutoresizingMaskIntoConstraints = false
        addSubview(collectionView)

        collectionView.topAnchor.constraint(equalTo: topAnchor).isActive = true
        collectionView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
        collectionView.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
        collectionView.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
    }
}

//HomeCell

class HomeCell: UICollectionViewCell {
    let posterImage = UIImageView()
    let movieName = UILabel()
    //...
}

Upvotes: 1

Related Questions