I'm building a list view with self-sizing in my app using UICollectionView
. Getting UICollectionViewFlowLayout
to do a vertical list layout is a pain, so I'm writing my own UICollectionViewLayout
subclass to do it.
My cells look a lot like regular table view cells - an image view on the left, a couple of labels vertically stacked in the center, and an accessory view on the right. The labels can wrap to a few lines and grow in font size according to the system font size setting, which is why they need to be self-sizing. Constraints are sensible - left to image view, image view to label, label to accessory, accessory to right, label to top and bottom.
To size my cells via preferredLayoutAttributesFittingAttributes
, I need to get the desired height of the cell given the width of the collection view. I'd expect to use systemLayoutSizeFittingSize:horizontalPriority:verticalPriority:
for this, passing a size like {desiredWidth, crazyLargeHeight}
, UILayoutPriorityRequired
for horizontal priority, and 1 for vertical priority. But the size I get back from systemLayoutFittingSize
isn't sensible. The width is some previous width value from the cell (which doesn't necessarily match self.bounds.size.width
or the passed-in layoutAttributes
' size.width
), and a height that works with that width. I also have tried passing a small height instead of a large one, and it still doesn't return the size it actually needs.
So how do I get the preferred height for the cell given a width value?
Sample code:
-(UICollectionViewLayoutAttributes *)preferredLayoutAttributesFittingAttributes:(UICollectionViewLayoutAttributes *)layoutAttributes
{
UICollectionViewLayoutAttributes *result = [super preferredLayoutAttributesFittingAttributes:layoutAttributes];
CGSize exampleSize = CGSizeMake(layoutAttributes.size.width, 20);
CGSize size = [self systemLayoutSizeFittingSize:exampleSize withHorizontalFittingPriority:UILayoutPriorityRequired verticalFittingPriority:1];
result.size = size;
return result;
}
Turns out if you ask the cell's content view for a size instead of the cell itself, it works. And you have to give a sample height that is smaller than will be needed.
I'm guessing that the content view isn't pinned to the cell's bounds the way I expected. And this exact implementation will likely fall down if the content view is inset for some reason. But the key to solving this was the fact that having the cell contents pinned to the cell's content view does not mean that the cell itself will compute a size as you expect.