UICollectionViewCompositionalLayoutで1つのgroup内のCellの高さを合わせる方法 uniformAcrossSiblings

# `UICollectionViewCompositionalLayout`で全てのCellの高さを合わせる方法 [uniformAcrossSiblings](https://developer.apple.com/documentation/uikit/nscollectionlayoutdimension/4173072-uniformacrosssiblings)

[uniformAcrossSiblings](https://developer.apple.com/documentation/uikit/nscollectionlayoutdimension/4173072-uniformacrosssiblings)を紹介します。

[What’s new in UIKit](https://developer.apple.com/jp/videos/play/wwdc2023/10055/)で紹介されていたものです。

`NSCollectionLayoutSize`の高さを`estimated`にすると、Cellの高さに応じてitemやgroupの高さが変化します。しかし、group内の高さは以下のようにバラバラになってしまいます。このようなケースでは、`uniformAcrossSiblings(estimate:)`で簡単に統一できます。`uniformAcrossSiblings(estimate:)`によって、group内で最大のitem高さに合わせて、他のitemの高さが変化します。

![Simulator Screenshot - iPhone 15 Pro - 2024-09-30 at 22.54.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373549/bc9b582b-7c6a-3eed-35ab-f900fbd69a30.png)

サンプルを貼ります。

```swift
import UIKit
import SwiftUI

class UniformSiblingsViewController: UIViewController {
    let layout: UICollectionViewCompositionalLayout = {
        let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0/3.0), heightDimension: .uniformAcrossSiblings(estimate: 80.0))
        let item = NSCollectionLayoutItem(layoutSize: itemSize)
        let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .estimated(80.0))
        let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, repeatingSubitem: item, count: 3)
        let section = NSCollectionLayoutSection(group: group)
        let layout = UICollectionViewCompositionalLayout(section: section)
        return layout
    }()
    lazy var collectionView: UICollectionView = {
        let collectionView = UICollectionView(frame: .zero, collectionViewLayout: self.layout)
        collectionView.translatesAutoresizingMaskIntoConstraints = false
        collectionView.delegate = self
        return collectionView
    }()
    var diffableDataSource: UICollectionViewDiffableDataSource<Section, Item>!
    override func viewDidLoad() {
        super.viewDidLoad()
        self.view.addSubview(self.collectionView)
        NSLayoutConstraint.activate([
            self.collectionView.topAnchor.constraint(equalTo: self.view.topAnchor),
            self.collectionView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor),
            self.collectionView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor),
            self.collectionView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor)
        ])
        let cellRegistration = UICollectionView.CellRegistration<UICollectionViewCell, Item>{ cell, indexPath, item in
            cell.contentConfiguration = UIHostingConfiguration(content: {
                VStack(spacing: 8){
                    Text(item.title)
                    Text(item.body)
                }
            })
            .background(item.background)
        }
        self.diffableDataSource = UICollectionViewDiffableDataSource(collectionView: self.collectionView, cellProvider: { collectionView, indexPath, item in
            collectionView.dequeueConfiguredReusableCell(using: cellRegistration, for: indexPath, item: item)
        })
        var snapShot = NSDiffableDataSourceSnapshot<Section, Item>()
        snapShot.appendSections([.main])
        snapShot.appendItems([
            Item(title: "hello, world", body: "hoge\nfoo\nbar", background: Color.red),
            Item(title: "hello\nworld", body: "hoge", background: Color.green),
            Item(title: "hello", body: "hoge", background: Color.blue),
        ])
        self.diffableDataSource.apply(snapShot, animatingDifferences: false)
    }
}

extension UniformSiblingsViewController {
    enum Section {
        case main
    }
    struct Item: Hashable {
        let title: String
        let body: String
        let background: Color
    }
}
```

![Simulator Screenshot - iPhone 15 Pro - 2024-09-30 at 22.49.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373549/c39f9831-25cb-eb8f-aa48-e0c823add0a7.png)

`layout`の定義を見てください。`group`を`estimated`に、`item`の高さを
`uniformAcrossSiblings(estimate:)`にしているのがポイントです。

```swift
    let layout: UICollectionViewCompositionalLayout = {
        let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0/3.0), heightDimension: .uniformAcrossSiblings(estimate: 80.0))
        let item = NSCollectionLayoutItem(layoutSize: itemSize)
        let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .estimated(80.0))
        let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, repeatingSubitem: item, count: 3)
        let section = NSCollectionLayoutSection(group: group)
        let layout = UICollectionViewCompositionalLayout(section: section)
        return layout
    }()
```