systemLayoutSizeFitting ignoring layout constraints and using image view intrinsic size

Nuno Gonçalves picture Nuno Gonçalves · Jun 28, 2017 · Viewed 8.1k times · Source

I'm using a custom layout for a UICollectionView. My cell should have fixed width and flexible height.

The cell is composed of a UImageView and a UIStackView. The UIImageView's constraints are the following:

image.top = cell.top
image.width = cell.width
image.height = image.width * 1.33
image.centerX = cell.centerX
image.bottom = stackView.top 

The stack view is similar, and is indeed tied to the bottom of the cell.

When the system is calling preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes {

I'm performing some calculations to get the height of the cell.

let preferredAttributes = super.preferredLayoutAttributesFitting(layoutAttributes)


let size = CGSize(width: layoutAttributes.frame.width,
                  height: UILayoutFittingCompressedSize.height)

let preferredSize = systemLayoutSizeFitting(size,
                                            withHorizontalFittingPriority: .defaultHigh,
                                            verticalFittingPriority: .fittingSizeLevel)

It turns out that the preferredSize is being calculated using the imageView instrinsic size rather than respecting the constraints. So for a image with 850x850, (and a cell with 160 points of width) I'm getting a much higher height than what I expect and therefore a cell with a huge space to the bottom.

I managed to solve this problem with something that I feel like it's a hack.

I created a reference to the width constraint of the image, update it when I call this method with the fixed value that I get from layoutAttributes and call setNeedsLayout() and layoutIfNeeded() and this works. But I really don't like that I have to force the layout to be done again and update the width myself, not to mention that I loose performance.

How can this be done in a better way?

Thank you very much.

Answer

iamirzhan picture iamirzhan · Jun 28, 2017

Are you have aspect ratio constraint? systemLayoutSizeFitting doesn't work properly when there is aspect ratio constraint.

First, try to set height constraint instead of aspect ratio on image and if it works, set the height constraint constant = image.width * 1.33 in code