Reputation: 329
I used auto layout to dynamically calculate the size of the collectionView cell. Some cells are using the dimensions from the reused cells when they first scrolled to view port. As I continue to scroll the collectionView, they will be set to the correct value.
In my sizeForItemAt
, I have the following:
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
if let cachedSize = cachedHeightForIndexPath[indexPath] {
return cachedSize
}
if let cell = collectionView.cellForItem(at: indexPath) {
cell.setNeedsLayout()
cell.layoutIfNeeded()
let size = cell.contentView.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize)
cachedHeightForIndexPath[indexPath] = size
print("value is \(size) for indexpath: \(indexPath)")
return size
}
return CGSize(width: ScreenSize.width, height: 0.0)
}
I have a three sessions, with the first section all cell's height theoretically equals to 88, and all the other sections all cell's height equals to 104.
Originally, only the first section is visible. From the console, I can see the height of the cell is set to 88.0 as expected. As I scroll to the remaining sections(the first section will be invisible and the cells will be reused), some cells from second section and third section are using the value 88.0 as the height of the cells when first scrolled to view port instead of 104. As I continue to scroll, the wrong sized cell will be using 104 as the dimension. How do we force all the cells to recalculate the height and don't use the height from old cell.
Upvotes: 0
Views: 1146
Reputation: 535889
You have the right idea, but when you measure the cell by its internal constraints by calling systemLayoutSizeFitting
, instead of calling systemLayoutSizeFitting
on an existing cell (collectionView.cellForItem
), you need to arm yourself with a model cell that you configure the same as cellForItem
would configure it and measure that.
Here's how I do it (remarkably similar to what you have, with that one difference; also, I store the size in the model):
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let memosize = self.sections[indexPath.section].itemData[indexPath.row].size
if memosize != .zero {
return memosize
}
self.configure(self.modelCell, forIndexPath:indexPath) // in common with cellForItem
var sz = self.modelCell.contentView.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize)
sz.width = ceil(sz.width); sz.height = ceil(sz.height)
self.sections[indexPath.section].itemData[indexPath.row].size = sz // memoize
return sz
}
Upvotes: 1