AutoSizing cells: cell width equal to the CollectionView

10,297

To implement self-sizing collection view cells you need to do two things:

  1. Specify estimatedItemSize on UICollectionViewFlowLayout
  2. Implement preferredLayoutAttributesFitting(_:) on your cell

1. Specifying estimatedItemSize on UICollectionViewFlowLayout

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. If all of your cells are the same height, use the itemSize property, instead of this property, to specify the cell size instead.

This is just an estimate which is used to calculate the content size of the scroll view, set it to something sensible.

let collectionViewFlowLayout = UICollectionViewFlowLayout()
collectionViewFlowLayout.estimatedItemSize = CGSize(width: collectionView.frame.width, height: 100)

2. Implement preferredLayoutAttributesFitting(_:) on your UICollectionViewCell subclass

override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes {
    let autoLayoutAttributes = super.preferredLayoutAttributesFitting(layoutAttributes)

    // Specify you want _full width_
    let targetSize = CGSize(width: layoutAttributes.frame.width, height: 0)

    // Calculate the size (height) using Auto Layout
    let autoLayoutSize = contentView.systemLayoutSizeFitting(targetSize, withHorizontalFittingPriority: UILayoutPriority.required, verticalFittingPriority: UILayoutPriority.defaultLow)
    let autoLayoutFrame = CGRect(origin: autoLayoutAttributes.frame.origin, size: autoLayoutSize)

    // Assign the new size to the layout attributes
    autoLayoutAttributes.frame = autoLayoutFrame
    return autoLayoutAttributes
}
Share:
10,297
Richard Topchii
Author by

Richard Topchii

Creator of CalendarKit: https://github.com/richardtop/CalendarKit iOS Development YouTube Channel: https://youtube.com/channel/UCx1gvWpy5zjOd7yZyDwmXEA

Updated on June 23, 2022

Comments

  • Richard Topchii
    Richard Topchii almost 2 years

    I'm using AutoSizing cells with Autolayout and UICollectionView.

    I can specify constraints in code on cell initialization:

      func configureCell() {
        snp.makeConstraints { (make) in
          make.width.equalToSuperview()
        }
      }
    

    However, the app crashes as the cell hasn't been yet added to the collectionView.

    Questions

    1. At which stage of the cell's lifecycle it is possible to add a constraint with cell's width?

    2. Is there any default way of making a cell'swidthequal to the widthof thecollectionViewwithout accessing an instance of UIScreenorUIWindow`?

    Edit The question is not duplicate, as it is not about how to use the AutoSizing cells feature, but at which stage of the cell lifecycle to apply constraints to achieve the desired result when working with AutoLayout.

  • Richard Topchii
    Richard Topchii about 6 years
    It's not an AutoSizing cells feature. I am familiar with this method. While it works perfectly, it looks rather like a hack.
  • Richard Topchii
    Richard Topchii about 6 years
    Thanks for the answer, it's the part 2 that I haven't implemented. With this approach the multitasking should work fine and there is no need to use the dummy-cell approach. I've updated your answer to match the latest Swift syntax.
  • Chris Conover
    Chris Conover almost 6 years
    This works for layout, but I could not get it to cleanly animate insertions, deletions, and cell expansion without using the delegate sizeForItem approach. If someone does have a clean solution for that, I would love to know. In the meantime, I have a sample with my various attempts here: github.com/chrisco314/CollectionView-AutoLayout. It works cleanly on the third tab, using sizeForItem...
  • Anand
    Anand almost 5 years
    Hey Oliver Thanks for posting. This works like charm
  • Vyachaslav Gerchicov
    Vyachaslav Gerchicov over 3 years
    what if I have cells of different size? Why must I set estimatedItemSize?
  • Oliver Atkinson
    Oliver Atkinson about 3 years
    estimatedItemSize is a guess to allow the scrollBar to work, it has to be set to allow for the collection view to perform the rest of the calculations