Adrian
Adrian

Reputation: 402

UITableView in UICollectionView

I placed a tableView inside a collectionView and added the delegates. The problem is, that I want to control the data in the different tableViews in the collectionView.

Every collectionView holds a label with the name of the current day (e.g.: "Monday"). Below the label is a tableView. In the tableView should be displayed different data, based on the index of the collectionView.

In my example, every tableView has two cells. The tableView in the first item of the collectionView should display: cell1: "1" and cell2: "2", the tableView in the second item should display: cell1: "3" and cell2: "4".

I'm currently using the code below:

    import UIKit

class StundenplanCollectionViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate, UITableViewDataSource, UITableViewDelegate {

    override func viewDidLoad() {
        super.viewDidLoad()

        myHours.append(myH0)
        myHours.append(myH1)
        myHours.append(myH2)
        myHours.append(myH3)
        myHours.append(myH4)
        myHours.append(myH5)

        collectionView.delegate = self
        collectionView.dataSource = self
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    //MARK: Outlets
    @IBOutlet weak var collectionView: UICollectionView!

    //MARK: Variables
    var myDays = ["Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag"]
    var myHours: [[String]] = Array() //Array that holds myH1 - myH5
    var myH0 = ["1", "2"]
    var myH1 = ["3", "4"]
    var myH2 = ["5", "6"]
    var myH3 = ["7", "8"]
    var myH4 = ["9", "10"]
    var myH5 = ["Error", "Error"]

    var tableLoop = 0

    var headerColor: UIColor = UIColor( red: CGFloat(255/255.0), green: CGFloat(140/255.0), blue: CGFloat(60/255.0), alpha: CGFloat(1.0))


    //MARK: Table and Collection View
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return myDays.count
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell: StundenplanCollectionViewCell = collectionView.dequeueReusableCell(withReuseIdentifier: "stundenplanCollectionCell", for: indexPath) as! StundenplanCollectionViewCell
        cell.titleLabel.text = myDays[indexPath.row]
        cell.titleLabel.backgroundColor = headerColor
        cell.titleLabel.textColor = UIColor.white
        return cell
    }


    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return myHours[tableLoop].count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell: StundenplanTableViewCell = tableView.dequeueReusableCell(withIdentifier: "stundenplanTableCell", for: indexPath) as! StundenplanTableViewCell
        cell.titleLabel.text = myHours[/*Here should the indexPath.row of the collectionView item be placed*/][indexPath.row]
        return cell
    }
}

class StundenplanCollectionViewCell: UICollectionViewCell {
    @IBOutlet weak var titleLabel: UILabel!
    @IBOutlet weak var tableView: UITableView!
}

class StundenplanTableViewCell: UITableViewCell {
    @IBOutlet weak var titleLabel: UILabel!
}

Image 1: Here you can see the first tableView in the collectionView (first item of collectionView):

image 1

Image 2: Here you can see the second tableView in the collectionView (second Item of collectionView):

image 2

Image 3: Storyboard:

image 3

Image 4: Structure of the different objects in the view:

image 4

Updated code (according to the answer by @missionMan - Thanks by the way!):

import UIKit

class StundenplanCollectionViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate {

    override func viewDidLoad() {
        super.viewDidLoad()

        navigationController?.navigationBar.prefersLargeTitles = false
        navigationController?.navigationBar.prefersLargeTitles = true
        navigationItem.largeTitleDisplayMode = .always

        myHours.append(myH0)
        myHours.append(myH1)
        myHours.append(myH2)
        myHours.append(myH3)
        myHours.append(myH4)
        myHours.append(myH5)

        collectionView.delegate = self
        collectionView.dataSource = self
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    //MARK: Outlets
    @IBOutlet weak var collectionView: UICollectionView!

    //MARK: Variables
    var myDays = ["Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag"]
    var myHours: [[String]] = Array() //Array that holds myH1 - myH5
    var myH0 = ["1", "2"]
    var myH1 = ["3", "4"]
    var myH2 = ["5", "6"]
    var myH3 = ["7", "8"]
    var myH4 = ["9", "10"]
    var myH5 = ["Error", "Error"]

    var headerColor: UIColor = UIColor( red: CGFloat(255/255.0), green: CGFloat(140/255.0), blue: CGFloat(60/255.0), alpha: CGFloat(1.0))


    //MARK: Table and Collection View
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return myDays.count
    }

    public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        guard let cell = tableView.dequeueReusableCell(withIdentifier: "stundenplanCollectionViewCell") as? StundenplanCollectionViewCell else { //how can I access the inner tableView? Error: Use of unresolved identifier 'tableView'
            return UICollectionViewCell()
        }

        //set data and reload inner table from outer view controller (StundenplanCollectionViewController according to your code)
        cell.dayItems = myHours[indexPath.row]
        cell.tableView.reloadData()
        //...

        return cell
    }


class StundenplanCollectionViewCell: UICollectionViewCell {
    @IBOutlet weak var titleLabel: UILabel!
    @IBOutlet weak var tableView: UITableView!
    var dayItems: [String] = []

    override func awakeFromNib() {
        super.awakeFromNib()
        self.tableView.delegate = self    // <-- set delegates inner table
        self.tableView.dataSource = self
    }
}

extension StundenplanCollectionViewCell: UITableViewDataSource, UITableViewDelegate {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return dayItems.count
    }

    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return 100
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell: StundenplanTableViewCell = (tableView.dequeueReusableCell(withIdentifier: "stundenplanTableViewCell") as? StundenplanTableViewCell)!
        //...
        return cell
    }
}

class StundenplanTableViewCell: UITableViewCell {
    @IBOutlet weak var titleLabel: UILabel!
}

Upvotes: 1

Views: 2111

Answers (2)

Ali Momen Sani
Ali Momen Sani

Reputation: 842

Why are you trying to dequeue a UICollectionViewCell from a UITableView?

public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCellWithReuseIdentifier(reuseIdentifier, forIndexPath: indexPath)
   ...
}

Upvotes: 0

missionMan
missionMan

Reputation: 903

You can add table delegate methods in table cell class and then you can set data for one day. So each collection cell will have its own table and its own data.

like this:

class StundenplanCollectionViewCell: UICollectionViewCell { //<-- outer cell
    @IBOutlet weak var titleLabel: UILabel!
    @IBOutlet weak var innerTableView: UITableView! //<-- declare inner table
    var dayItems: [String] = []

    override func awakeFromNib() {
        super.awakeFromNib()
        self.innerTableView.delegate = self    // <-- set delegates inner table
        self.innerTableView.dataSource = self
    }
}

extension StundenplanCollectionViewCell: UITableViewDataSource, UITableViewDelegate {

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return dayItems.count
    }

    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        ...
    }

        ...

set data from outer cell of your collectionView in StundenplanCollectionViewController

public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    guard let cell = collectionView.dequeueReusableCell(withIdentifier: "stundenplanCollectionViewCell") as? StundenplanCollectionViewCell else { //<-- HERE
        return UICollectionViewCell()
    }

    //set data and reload inner table from outer view controller (StundenplanCollectionViewController according to your code)
    cell.dayItems = myH[indexPath.row]
    cell.innerTableView.reloadData()
    ...

    return cell
}

Upvotes: 2

Related Questions