Search code examples
iosswiftuicollectionviewselfsizing

UICollectionView .reloadData() only shows sections


I have a collection view which has a section with a title and every section has some words. Words differ in size.

Because the words differ in size i've added the following, to prevent long words from being cut off: layout.estimatedItemSize = CGSize(width: 1.0, height: 1.0)

However after setting that and invoking reloadData(), the cells (words) do not get loaded only the sections (title).

But after scrolling all the sections that went out of screen will load their words. However when I don't use layout.estimatedItemSize it works correctly, but the words are cut off.

So my question is if there is another way to display those words (which are basically a small view with a label) without them being cut off. Or am I using estimatedSize wrongly?

As I read from the docs from apple itself: docs The default value of this property is CGSizeZero. Setting it to any other value causes the collection view to query each cell for its actual size using the cell’s preferredLayoutAttributesFitting(_:) method.

I do set constraints dynamically and statically (StoryBoard), my dynamic constraint is as following:

if prevCell != nil {
    let constraint = NSLayoutConstraint(item: cell, attribute: NSLayoutAttribute.leading, relatedBy: NSLayoutRelation.equal, toItem: prevCell, attribute: NSLayoutAttribute.trailing, multiplier: 1.0, constant: 5.0)
    cell.addConstraint(constraint)
    self.prevCell = cell
}

Things I have tried myself so far:

//before reload data invalidate the layout
    self.collectionView!.collectionViewLayout.invalidateLayout()
    self.collectionView!.reloadData()

Solution

  • After some more research found the correct way to handle this. I forgot to override the preferredLayoutAttributesFitting in the cell's class. To make it work I just left the layout.estimatedItemSize = CGSize(width: 1.0, height: 1.0) in viewDidLoad of the collection view.

    However somehow this is not enough because it wont be able to calculate the right size not until you scroll it out of screen. It probably has some logic behind it that I do not know of.

    But when overriding the the preferredLayoutAttributesFitting as follow:

        override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes {
            setNeedsLayout()
            layoutIfNeeded()
            let updatedSize = contentView.systemLayoutSizeFitting(layoutAttributes.size)
            var updatedFrame = layoutAttributes.frame
            updatedFrame.size.width = CGFloat(ceilf(Float(updatedSize.width)))
            updatedFrame.size.height = CGFloat(ceilf(Float(updatedSize.height)))
            layoutAttributes.frame = updatedFrame
            return layoutAttributes
        }