Influencing a `UICollectionViewCell`'s fitting priority from within a custom `UICollectionViewLayout`

When using a custom UICollectionViewLayout that makes use of self-sizing cells, it isn't clear to me how to influence the fitting priority sent to the cell's content view via systemLayoutSizeFitting(_:withHorizontalFittingPriority:verticalFittingPriority:) as part of UICollectionViewCell's default implementation of preferredLayoutAttributesFitting(_:).

For example, take a simple self-sizing cell with a basic UIContentView conforming content view that pins a UILabel to each edge using auto-layout:

If I use this cell with a stock list layout (i.e. UICollectionViewCompositionalLayout.list(using: .init(.plain)) ), I can see that when the collection view is laid out, each cell's content view has its systemLayoutSizeFitting(_:withHorizontalFittingPriority:verticalFittingPriority:) method called with the horizontal fitting priority set to .required/1000.

However, when using a custom layout, the fitting priority remains at .fitting/50.

How does UICollectionViewCompositionalLayout achieve this considering the cell is using its default implementation of preferredLayoutAttributesFitting(_:)? Is there a way of specifying the fitting priority from within a layout?

Accepted Reply

When UICollectionViewCompositionalLayout performs self-sizing of cells, it internally configures these priorities on the cell, based on whether the item's width & height are estimated.

If you are implementing a custom UICollectionViewLayout and want to constrain one axis (e.g. so the height is dependent on the width, or vice versa), you will need to override preferredLayoutAttributesFitting(_:) in your cell and call self.systemLayoutSizeFitting(_:withHorizontalFittingPriority:verticalFittingPriority:) with the desired UILayoutPriority values. Consider having your data source consult with your layout and set these priorities to properties on your cell when you dequeue the cell, so that when the cell receives preferredLayoutAttributesFitting(_:) later it can simply use the previously-configured values stored in its properties.

Replies

When UICollectionViewCompositionalLayout performs self-sizing of cells, it internally configures these priorities on the cell, based on whether the item's width & height are estimated.

If you are implementing a custom UICollectionViewLayout and want to constrain one axis (e.g. so the height is dependent on the width, or vice versa), you will need to override preferredLayoutAttributesFitting(_:) in your cell and call self.systemLayoutSizeFitting(_:withHorizontalFittingPriority:verticalFittingPriority:) with the desired UILayoutPriority values. Consider having your data source consult with your layout and set these priorities to properties on your cell when you dequeue the cell, so that when the cell receives preferredLayoutAttributesFitting(_:) later it can simply use the previously-configured values stored in its properties.

it internally configures these priorities on the cell, based on whether the item's width & height are estimated.

That's good to know, thank you. I will adopt your recommended approach.

When overriding preferredLayoutAttributesFitting(_:) is it necessary to make a copy of the layout attributes provided or are we safe to simply modify the reference directly?

I'm using the latter and not seeing any issues, but there's some conflicting information out there on the whether or not this is the right thing to do. I imagine you'd make a copy of any user generated layout attribute refs at the API boundaries, but would be good to have this confirmed.

Also, I think it would be great if there were consistency between how a cell should be implemented when used with a stock Apple layout vs a custom layout. This would mean we could use stock Apple cells in our custom layouts without sub-classing the cells. Perhaps by exposing the fitting priorities as properties of UICollectionViewLayoutAttributes.