Post

Replies

Boosts

Views

Activity

How to: Compositional layout with self-sizing rows of N columns where the height of each item is set to the tallest item in its row
Paging Steve Breen! 😄 I've seen this question asked a zillion times but I've never seen an answer. Is it possible to configure compositional layout to give you a grid of N columns (say 2 or 3) where each item in each row/group self-size their height, but the heights of those items are then set to be the height of the tallest item in their row. This is easy to do if you ignore the self-sizing requirement (just use a fixed or absolute item height), but on the surface this doesn't even appear to be possible if you require self-sizing. What I've Tried Configuring a layout where the items are set to a fractional height of 1.0 and their group is set to an estimated height (ex: 100). I was hoping compositional layout would interpret this as, "Please self-size the height of the group and make each item 100% of that height." Unfortunately, compositional layout just uses the estimate you provide for the height as the actual height and no self-sizing occurs at all. Sad panda. 🐼 Use visibleItemsInvalidationHandler to attempt to identify which items share a row and reset their heights to be the height of the tallest item in that row. Sadly, the handler doesn't really have access to the data it needs to do this, nor is it allowed to change frames, nor is it called on the first layout pass, nor does it appear to be supported at all for layouts containing estimated items. In fact, if you try to use it with layouts that support self-sizing, you'll get this error message: [UICompositionalLayout] note: the section invalidation handler cannot currently mutate visible items for layouts containing estimated items. Please file an enhancement request on UICollectionView. Wishing upon a star. Oh, and I also filed a radar asking: FB11776888 Here's a visual aid: I have a little test program as well, but unfortunately I can't upload it here. Happy to share if it would be helpful. Here are a couple snippets: #1 // This doesn't work     private func makeLayout1() -> UICollectionViewCompositionalLayout {         // Item         let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(0.5), heightDimension: .fractionalHeight(1))         let item = NSCollectionLayoutItem(layoutSize: itemSize)         // Group         let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .estimated(100))         let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, repeatingSubitem: item, count: 2)         group.interItemSpacing = .fixed(10)         // Section         let section = NSCollectionLayoutSection(group: group)         return UICollectionViewCompositionalLayout(section: section)     } #2 // This self-sizes the heights of the items, but allows the items in each row to be different heights rather than providing any way to constrain them to the height of the tallest self-sized item in each row     private func makeLayout2() -> UICollectionViewCompositionalLayout {         // Item         let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(0.5), heightDimension: .estimated(100))         let item = NSCollectionLayoutItem(layoutSize: itemSize)         // Group         let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .estimated(100))         let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, repeatingSubitem: item, count: 2)         group.interItemSpacing = .fixed(10)         // Section         let section = NSCollectionLayoutSection(group: group)         return UICollectionViewCompositionalLayout(section: section)     } Options? My guess is that compositional layout simply doesn't support layouts that require a "partial second pass" per group, where the frames of the items can be updated based on information collected during self-sizing the other items in the group (to, for example, force them all to a common height, or align them top/bottom/centered within their group). If that's the case (not supported), I would love a suggestion for where I might override the layout to provide this capability. Thank you! ❤️
4
5
4.5k
Nov ’22