UICollectionViewFlowLayoutでセルの大きさやセル同士の間隔などを設定する

UICollectionViewFlowLayoutはビルトインで用意されているUICollectionViewのレイアウトオブジェクトです。
UICollectionViewのレイアウトはデフォルトでUICollectionViewFlowLayoutが使用されます。
UICollectionViewFlowLayoutはセルの大きさやセル同士の間隔、セクションごとの余白の大きさなどを設定するプロパティを持っており、これらを変更することでレイアウトを変更することができます。
ここではこれらのプロパティを設定し、レイアウトが変更される様子をご紹介します。

なお、本記事では説明に必要な箇所のコードのみ掲載しています。
ベースとなる実装については以下の記事を参照してください。

[UICollectionViewを必要最低限のコードで実装してみる](https://qiita.com/takehilo/items/4af35623aadf3c59dc65)

## デフォルトのレイアウト
各プロパティにはデフォルト値があり、デフォルトのままだと以下のようなレイアウトになります。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/81715/db3641fd-7df9-a19e-fcb2-29a040d918dd.png)

## セルの大きさを変更する
`itemSize`プロパティでセルの大きさを変更してみます。
デフォルトではセルの幅は50なので、ここでは倍の100にしてみます。

```swift
override func viewDidLoad() {
    super.viewDidLoad()

    collectionView.dataSource = self

    collectionView.backgroundColor = .lightGray

    // レイアウト設定
    let layout = UICollectionViewFlowLayout()
    layout.itemSize = CGSize(width: 100, height: 50)
    collectionView.collectionViewLayout = layout
}
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/81715/72eb66f6-106b-39f3-0f03-93eca1d41dd1.png)

## セル同士の間隔の長さを変更する
`minimumInteritemSpacing`プロパティでセル同士の間隔の長さを変更してみます。
デフォルトではこのプロパティの値は10に設定されていますので、ここでは50にしてみます。

```swift
override func viewDidLoad() {
    super.viewDidLoad()

    collectionView.dataSource = self

    collectionView.backgroundColor = .lightGray

    // レイアウト設定
    let layout = UICollectionViewFlowLayout()
    layout.minimumInteritemSpacing = 50
    collectionView.collectionViewLayout = layout
}
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/81715/11a37e7a-c8ac-57b9-b65f-9eb5f9a1a9b9.png)

セル同士の間隔が広くなりました。
ここで1点注意なのは、このプロパティで設定できるのは長さの**最小値**であるということです。
UICollectionViewFlowLayoutは行の最後のセルが行末にぴったりくるように配置するために、セル同士の間隔を自動調整します。
その際、`minimumInteritemSpacing`の値よりも間隔が長くなる可能性があります。
実際、上図ではセル同士の間隔の長さは約58です。

## 行間の長さを変更する
`minimumLineSpacing`プロパティでセル同士の間隔の長さを変更してみます。
デフォルトではこのプロパティの値は10に設定されていますので、ここでは50にしてみます。

```swift
override func viewDidLoad() {
    super.viewDidLoad()

    collectionView.dataSource = self

    collectionView.backgroundColor = .lightGray

    // レイアウト設定
    let layout = UICollectionViewFlowLayout()
    layout.minimumLineSpacing = 50
    collectionView.collectionViewLayout = layout
}
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/81715/0160c99b-bccb-0771-ac21-5bca0223a77a.png)

行間の長さが広くなりました。
`minimumInteritemSpacing`と同じように、このプロパティで設定できる行間の長さも**最小値**になります。
以下の図のように、セルごとに高さがばらばらの場合、各行ごとに最大の高さを選択し、行間の長さが均等になるように自動調整されます。
その結果、指定した値よりも長くなる可能性があります。

([Collection View Programming Guide for iOS](https://developer.apple.com/library/content/documentation/WindowsViews/Conceptual/CollectionViewPGforIOS/UsingtheFlowLayout/UsingtheFlowLayout.html)より)
![image.png](https://qiita-image-store.s3.amazonaws.com/0/81715/09af9dbd-a942-a2d6-adbc-866352f7bdb4.png)

## 余白を変更する
`sectionInset`プロパティでレイアウトに余白を与えることができます。
余白は各セクションのヘッダー後、フッター前に差し込まれる形になります。

([Collection View Programming Guide for iOS](https://developer.apple.com/library/content/documentation/WindowsViews/Conceptual/CollectionViewPGforIOS/UsingtheFlowLayout/UsingtheFlowLayout.html)より)
![image.png](https://qiita-image-store.s3.amazonaws.com/0/81715/b391c26e-b25c-8363-e372-07caea41c330.png)

ここではセクション数を2つに増やし、余白が差し込まれる様子を見てみます。
上下左右それぞれ余白を24に設定します。

```swift:ViewController.swift
import UIKit

class ViewController: UIViewController {
    @IBOutlet weak var collectionView: UICollectionView!

    override func viewDidLoad() {
        super.viewDidLoad()

        collectionView.dataSource = self
        collectionView.delegate = self

        collectionView.backgroundColor = .lightGray

        // レイアウト設定
        let layout = UICollectionViewFlowLayout()
        layout.sectionInset = UIEdgeInsets(top: 24, left: 24, bottom: 24, right: 24)
        collectionView.collectionViewLayout = layout
    }
}

extension ViewController: UICollectionViewDataSource {
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 10
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath)
        cell.backgroundColor = .red

        return cell
    }

    // 追加
    func numberOfSections(in collectionView: UICollectionView) -> Int {
        return 2
    }
}
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/81715/61888103-f7b0-9c62-db37-7468572ce422.png)

セクションの上下左右に余白が追加されました。
セクション1の下とセクション2の上それぞれに余白が入っているため、セクション間の余白が大きくなっています。