I have a TableView
.
Each UITableViewCell
is a UICollectionView
.
Each UICollectionViewCell
has only an image.
For some reason, my UICollectionView
shows only one cell, even though my model has more.
What am I missing here?
Sharing my code:
ProductsVC
import UIKit
class ProductsVC: UIViewController
{
@IBOutlet weak var categories: UITableView!
override func viewDidLoad()
{
super.viewDidLoad()
categories.delegate = self
categories.dataSource = self
self.categories.separatorStyle = .none
self.categories.register(UINib(nibName: "CategoryCell", bundle: nil), forCellReuseIdentifier: "categoryCell")
}
}
extension ProductsVC: UITableViewDelegate, UITableViewDataSource
{
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell = categories.dequeueReusableCell(withIdentifier: "categoryCell", for: indexPath) as! CategoryCell
cell.listOfProducts = Utils.inventory[indexPath.section].listOfProducts
return cell
}
func numberOfSections(in tableView: UITableView) -> Int
{
return Utils.inventory.count
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView?
{
let headerText = UILabel()
headerText.textColor = UIColor.systemPink
headerText.adjustsFontSizeToFitWidth = true
headerText.textAlignment = .right
headerText.frame = CGRect(x: 20, y: 20, width: UIScreen.main.bounds.width - 40, height: 20)
headerText.font = UIFont.boldSystemFont(ofSize: 25)
headerText.text = Utils.inventory[section].name
headerText.backgroundColor = .clear
let headerView = UIView()
headerView.addSubview(headerText)
return headerView
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat
{
let bounds = UIScreen.main.bounds
let height = bounds.size.height
return (height - (CGFloat(Utils.inventory.count) * 70))/CGFloat(Utils.inventory.count)
}
}
CategoryCell
import UIKit
class CategoryCell: UITableViewCell
{
@IBOutlet private weak var products: UICollectionView!
var listOfProducts: [Product] = []
override func awakeFromNib()
{
super.awakeFromNib()
self.products.delegate = self
self.products.dataSource = self
self.products.register(UINib(nibName: "ProductCell", bundle: nil), forCellWithReuseIdentifier: "productCell")
}
override func setSelected(_ selected: Bool, animated: Bool)
{
super.setSelected(selected, animated: animated)
}
}
extension CategoryCell: UICollectionViewDelegate, UICollectionViewDataSource
{
func numberOfSections(in collectionView: UICollectionView) -> Int
{
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
{
return listOfProducts.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = products.dequeueReusableCell(withReuseIdentifier: "productCell", for: indexPath) as! ProductCell
cell.productImage.image = listOfProducts[indexPath.row].image
let height = UIScreen.main.bounds.height
let frameHeight = ((height - (CGFloat(Utils.inventory.count) * 70))/CGFloat(Utils.inventory.count)) - 60
cell.frame = CGRect(x: 20, y: 50, width: frameHeight, height: frameHeight)
cell.productImage.frame = CGRect(x: 0, y: 0, width: frameHeight, height: frameHeight)
Utils.makeControlRound(layer: cell.layer, borderWidth: 1, cornerRadius: 25, borderColor: cell.layer.backgroundColor)
return cell
}
}
ProductCell
import UIKit
class ProductCell: UICollectionViewCell
{
@IBOutlet weak var productImage: UIImageView!
override func awakeFromNib()
{
super.awakeFromNib()
Utils.makeControlRound(layer: self.layer, borderWidth: 1, cornerRadius: 25, borderColor: #colorLiteral(red: 1, green: 1, blue: 1, alpha: 0))
Utils.makeControlRound(layer: self.productImage!.layer, borderWidth: 1, cornerRadius: 25, borderColor: #colorLiteral(red: 1, green: 1, blue: 1, alpha: 0))
}
}
Also - is there a way to present (show modally) a different UIViewController
when I click the UICollectionViewCell
?
You're going to want to pass a closure to the tableView cell so that when one of the collectionView cells is selected the tableView controller will know about it. onProductSelected
is what you want to be paying attention to here.
class CategoryCell: UITableViewCell {
var onProductSelected: ((Product) -> Void)?
var listOfProducts: [Product] = []
}
extension CategoryCell: UICollectionViewDelegate, UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
onProductSelected?(listOfProducts[indexPath.item])
}
}
class ProductsVC: UIViewController {
@IBOutlet weak var categories: UITableView!
func presentViewController(for product: Product) {
// Whatever
}
}
extension ProductsVC: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = categories.dequeueReusableCell(withIdentifier: "categoryCell", for: indexPath) as! CategoryCell
cell.onProductSelected = { [unowned self] product in
self.presentViewController(for: product)
}
cell.listOfProducts = [] // Whatever
return cell
}
}
Hope that helps.