Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UICollectionViewCell dynamic height w/two dynamic labels & auto layout

I have a UICollectionViewCell subclass that's setup with a prototype cell and constraints (every view is connected both vertically and horizontally).

I have two labels that can vary in size, they can be either one or two lines. To that end I have set two height constraints on each label, one with a greater than or equal (16 or 20 depending on the label) and a less than or equal (32 or 40 depending on the label).

The number of lines on the labels are set to 0. (Though I have tried a variety of settings).

Since I've used auto layout and constraints to setup the view I've specified a width on the content view in the cell's awakeFromNib()

override func awakeFromNib() {
        NSLayoutConstraint.activate([contentView.widthAnchor.constraint(equalToConstant: 341)])
        super.awakeFromNib()
        configureBorder()
}

On the collectionView's layout I've specified the automaticDimension constant for estimateItemSize & itemSize

if let flowLayout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout {
    flowLayout.estimatedItemSize = UICollectionViewFlowLayoutAutomaticSize
    flowLayout.itemSize = UICollectionViewFlowLayoutAutomaticSize
}

With the idea of using auto layout I have not implemented a delegate on the collection view.

I am experiencing very inconsistent layout, some instances the cell's will appear as I'd like them to, in others the labels are truncated and in others the labels are extremely narrow and display text over three lines.

I have tried many things, including calling .sizeToFit() on each label after it's text property is set, as well as calling .setNeedsDisplay() before the cell returns from cellForItemAt

I'm wondering what is the right way to do this with storyboard constraints. I've worked with some of the popular answers to similar questions here on SO, though none to any real success.

like image 283
Fred Faust Avatar asked Jul 30 '18 01:07

Fred Faust


1 Answers

flowLayout.estimatedItemSize = UICollectionViewFlowLayoutAutomaticSize
flowLayout.itemSize = UICollectionViewFlowLayoutAutomaticSize

Of course I am familiar with Apple's repeated claims that a UICollectionViewCell in a UICollectionViewFlowLayout can be self-sizing based on internal constraints. But I have never seen working code from Apple that demonstrated this feature, and I have never once myself succeeded in confirming those claims to be true. I do not believe there is really such a thing as a self-sizing cell. For years, trying to get a cell to be self-sizing resulted in crashes. In iOS 10, the crashing mostly stopped, but now the flow layout was not laying out the cells correctly (which sounds like what you're seeing).

Naturally, I have filed bugs on all this, year after year.

Meanwhile, what I do is to give the collection view a delegate and implement collectionView(_:layout:sizeForItemAt:), and I suggest that you should do the same.


EDIT New in iOS 13 you can use a composable layout and abandon UICollectionViewFlowLayout altogether. Self-sizing cells work fine in a composable layout.

like image 106
matt Avatar answered Nov 06 '22 20:11

matt