Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Non-Scrolling UICollectionView inside UITableViewCell Dynamic Height

I have added UICollectionView inside UITableViewCell, for that I have created XIB file. Check following image:

UITableView Xib

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.

like image 533
Mayur Karmur Avatar asked Dec 17 '22 18:12

Mayur Karmur


1 Answers

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

like image 162
dahiya_boy Avatar answered May 22 '23 05:05

dahiya_boy