I have added UICollectionView
inside UITableViewCell
, for that I have created XIB
file. Check following image:
You can see in above image all view's hierarchy and constraints.
Note: I have disable collection view vertical and horizontal scrolling because I want to increase
UITableViewCell
height dynamically. So I have taken collection view's height's constraint's outlet and changing it programatically based on item available in collection view.
Collection view's item size if fixed, width is proportional to collection view and height is 30
I have register this xib with my table view by using following code.
self.tblSubCategory.register(SubCategoryTVC.Nib(), forCellReuseIdentifier: "SubCategoryTVC")
Here is my code of SubCategoryTVC
:
class SubCategoryTVC: UITableViewCell {
@IBOutlet weak var categoryView : UIView!
@IBOutlet weak var categoryImageView : UIView!
@IBOutlet weak var imgCategory : UIImageView!
@IBOutlet weak var lblCategoryName : UILabel!
@IBOutlet weak var cvSubcategory : UICollectionView!
// MARK: Constrains's Outlet
@IBOutlet weak var const_cvSubcategory_height : NSLayoutConstraint!
class func Nib() -> UINib {
return UINib(nibName: "SubCategoryTVC", bundle: nil)
}
func setCollectionView(dataSourceDelegate: UICollectionViewDataSource & UICollectionViewDelegate, forRow row: Int) {
self.cvSubcategory.delegate = dataSourceDelegate
self.cvSubcategory.dataSource = dataSourceDelegate
self.cvSubcategory.tag = row
self.cvSubcategory.reloadData()
}
override func awakeFromNib() {
super.awakeFromNib()
}
}
UITableViewDataSource:
extension SignupSecondStepVC: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 5
}
//------------------------------------------------------------------------------
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "SubCategoryTVC", for: indexPath) as! SubCategoryTVC
cell.lblCategoryName.text = "Category \(indexPath.row)"
cell.cvSubcategory.register(SubCategoryCVC.Nib(), forCellWithReuseIdentifier: "SubCategoryCVC")
return cell
}
}
UITableViewDelegate:
extension SignupSecondStepVC: UITableViewDelegate {
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
guard let subCategoryCell = cell as? SubCategoryTVC else { return }
// This line of code set dataSource and delegate to `SignupSecondStepVC` instead of `SubCategoryTVC`
subCategoryCell.setCollectionView(dataSourceDelegate: self, forRow: indexPath.row)
subCategoryCell.cvSubcategory.setNeedsLayout()
// This will change height of collection view based on item available.
subCategoryCell.const_cvSubcategory_height.constant = 30 * 5
subCategoryCell.cvSubcategory.setNeedsLayout()
subCategoryCell.contentView.layoutIfNeeded()
}
//------------------------------------------------------------------------------
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
//------------------------------------------------------------------------------
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
}
Above code for UITableView
, Please see following code of UICollectionView
UICollectionViewDataSource:
extension SignupSecondStepVC: UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 5
}
//------------------------------------------------------------------------------
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "SubCategoryCVC", for: indexPath) as! SubCategoryCVC
cell.btnSelection.setCornerRadius(radius: cell.btnSelection.frame.size.height / 2)
cell.lblSubCategoryName.text = "SubCategory \(indexPath.row)"
return cell
}
}
UICollectionViewDelegateFlowLayout:
extension SignupSecondStepVC: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let width = collectionView.frame.size.width
return CGSize(width: width, height: 30)
}
}
After all these things done, I have issue with cell loading and UI. When I run app and load data first time getting issue of UI and not proper data loading. See following video, So you can understand my actual issue.
Issue Video
Please help me to fix this issue.
You need to bind your collectionView delegate/datasource with TableViewCell and need to use below func in tableViewcell. Make sure to turn off the CollectionView Scrolling.
override func systemLayoutSizeFitting(_ targetSize: CGSize, withHorizontalFittingPriority horizontalFittingPriority: UILayoutPriority, verticalFittingPriority: UILayoutPriority) -> CGSize {
self.layoutIfNeeded()
let contentSize = self.cvSubcategory.collectionViewLayout.collectionViewContentSize
if self.cvSubcategory.numberOfItems(inSection: 0) < 4 {
return CGSize(width: contentSize.width, height: 120) // Static height if colview is not fitted properly.
}
return CGSize(width: contentSize.width, height: contentSize.height + 20) // 20 is the margin of the collectinview with top and bottom
}
Your project sample solution : https://github.com/thedahiyaboy/DynamicCollectionApp
For future purpose you can take ref from this post : Dynamic CollectionViewCell In TableViewCell Swift
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With