Home > Blockchain >  UICollectionView inside UITableviewCell give wrong contentSizeHeight at first time but becomes true
UICollectionView inside UITableviewCell give wrong contentSizeHeight at first time but becomes true

Time:04-09

I have a view that structured like this

-Tableview
   - TableviewCell
       - UICollectionView
          - UICollectionViewCell

the uicollectionview cell defines a left align tag with collectionViewFlowLayout like this

class Row {
    var attributes = [UICollectionViewLayoutAttributes]()
    var spacing: CGFloat = 0

    init(spacing: CGFloat) {
        self.spacing = spacing
    }

    func add(attribute: UICollectionViewLayoutAttributes) {
        attributes.append(attribute)
    }

    func tagLayout(collectionViewWidth: CGFloat) {
        let padding = 0
        var offset = padding
        for attribute in attributes {
            attribute.frame.origin.x = CGFloat(offset)
            offset  = Int(attribute.frame.width   spacing)
        }
    }
}

class LeftAlignTagCollectionViewFlowLayout: UICollectionViewFlowLayout {
    override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
        guard let attributes = super.layoutAttributesForElements(in: rect) else {
            return nil
        }

        var rows = [Row]()
        var currentRowY: CGFloat = -1

        for attribute in attributes {
            if currentRowY != attribute.frame.origin.y {
                currentRowY = attribute.frame.origin.y
                rows.append(Row(spacing: 4))
            }
            rows.last?.add(attribute: attribute)
        }

        rows.forEach {
            $0.tagLayout(collectionViewWidth: collectionView?.frame.width ?? 0)
        }
        return rows.flatMap { $0.attributes }
    }
}

this is code at datasource cellForRow in ViewController that handle tableview

let cell = tableView.dequeueReusableCell(withIdentifier: "CollectionTableViewCell") as? CollectionTableViewCell
cell?.setupCell(showFirstItem: true, showSecondItem: true)
cell?.collectionView.reloadData()
cell?.layoutIfNeeded()
let height = cell?.collectionView.collectionViewLayout.collectionViewContentSize.height
cell?.collectionViewHeightConstraint.constant = height ?? 0

i have already call layoutIfNeeded() before accessing collectionview content size height and assign the contentsize height into collectionview height constraint. i already set isScrollEnabled to false.

and in the CollectionTableViewCell it looks like this

@IBOutlet weak var collectionView: UICollectionView!
@IBOutlet weak var collectionViewHeightConstraint: NSLayoutConstraint! // Required priority (1000)

private var collectionItem: [String] = []
    
    override func awakeFromNib() {
        super.awakeFromNib()
        setupCollectionView()
        collectionView.dataSource = self
        collectionView.delegate = self
        let layout = LeftAlignTagCollectionViewFlowLayout()
        layout.estimatedItemSize = CGSize(width: 140, height: 40)
        collectionView.collectionViewLayout = layout
    }

    func setupCell(showFirstItem: Bool, showSecondItem: Bool)  {
        setupCollectionItem()
    }

    private func setupCollectionItem(showFirstItem: Bool, showSecondItem: Bool) {
        collectionItem = []
        if showFirstItem {
            let data = "TagNumber1"
            collectionItem.append(data)
        }
        
        if showSecondItem {
            let data = "TagNumber2"
            collectionItem.append(data)
        }
    }

extension CollectionTableViewCell: UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
    private func setupCollectionView() {
        collectionView.register(UINib(nibName: "CollectionViewCell", bundle: nil), forCellWithReuseIdentifier: "CollectionViewCell")
    }
    
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return collectionItem.count
    }
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CollectionViewCell", for: indexPath) as? CollectionViewCell
        cell?.configCell(model: collectionItem[indexPath.row], maxWidth: collectionView.frame.width - 8)
        cell?.setNeedsLayout()
        cell?.layoutIfNeeded()
        return cell ?? UICollectionViewCell()
    }
}

in summary, when i run the code above, it will give wrong content size height at first load lets say around 86.0 but after scrolling or reload tableview for the second time (i have two times reload tableview since there are two method for calling API in this ViewController) it gives correct number lets say the target that i want is 24.0 so when changing from first value 86.0 to 24.0 it gives a glitch in uitableviewcell. and i cannot hide the tableview until finish the process of collectionview height calculation. Another point is, if i have only one item at collectionItem it gives correct contentsize height! but when it turns into two items the problem showed.

waiting for your suggestion, Thank you

CodePudding user response:

This is inherently problematic, for a couple reasons...

First, collection views have a couple of primary benefits:

  1. automatic scrolling
  2. memory management via cell reuse

when writing code to "auto-size" a collection view, both of those benefits are thrown away.

Second, when table view cell is first instantiated, it doesn't know what its actual width will be. So when the collection view lays out its cells, it uses whatever width it starts with -- if it's setup as a cell prototype in Storyboard, for example, it will use the width from the Storyboard.

If you search for uicollectionview inside uitableviewcell dynamic height you'll find many discussions and attempts to get this to work, with varying success.

However, because - as mentioned above - you're not using two of the "best features" of collection views, you may want to take a different approach.

Take a look at this answer to a similar "tags layout" question. You may find it easier to work with: https://stackoverflow.com/a/60588546/6257435

  • Related