【Swift】CollectionViewでカスタムheaderとfooterを作成する

#はじめに
今回はCollectionViewでheaderとfooterを扱う方法を紹介したいと思います。
以下のようなものを作ってみます。
![ezgif.com-gif-maker (2).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/954451/f756a9fe-899c-dc0d-75ed-bc795ce14684.gif)

#GitHub
以下の`HeaderFooterCollectionView`に今回のリポジトリあります！

https://github.com/0429oonishi/CollectionViews

#実装
まず、真ん中の赤い正方形を作ります。
カスタムセルでXIBを作成してコードは以下のようにしてください。

```swift:MyCollectionViewCell
final class MyCollectionViewCell: UICollectionViewCell {
        
    static var toString: String {
        return String(describing: self)
    }
    static let id = MyCollectionViewCell.toString
    static func nib() -> UINib {
        return UINib(nibName: MyCollectionViewCell.toString, bundle: nil)
    }
    
    func configure() {
        backgroundColor = .red
    }
    
}
```

そして、`ViewController`の`viewDidLoad`以下のように、`UICollectionViewFlowLayout`を利用します。

```swift:ViewController
 let layout = UICollectionViewFlowLayout()
        layout.scrollDirection = .vertical
        layout.sectionInset = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
        layout.itemSize = CGSize(width: self.view.frame.size.width / 2.2,
                                 height: self.view.frame.size.width / 2.2)
        collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
        collectionView?.register(MyCollectionViewCell.nib(),
                                 forCellWithReuseIdentifier: MyCollectionViewCell.id)
        collectionView?.delegate = self
        collectionView?.dataSource = self
        collectionView?.backgroundColor = .white
        view.addSubview(collectionView!)
}
```

`collectionView`の縦横のサイズを決めます。

```swift:ViewController
override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        collectionView?.frame = self.view.bounds
}
```

そして、delegateメソッドを以下のように書きます。

```swift:ViewController
extension ViewController: UICollectionViewDataSource {
    
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 4
    }
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: MyCollectionViewCell.id, for: indexPath) as! MyCollectionViewCell
        cell.configure()
        return cell
    }

}
```

これで真ん中に表示4つの赤い正方形が表示されたと思います。

次はheaderを作成していきます。
headerやfooterは以下のような`UICollectionReusableView`というものを使います。
![スクリーンショット 2021-04-05 12.24.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/954451/b48ed56d-9c65-28f1-a96b-4c2a9e3eb305.png)

```swift:HeaderCollectionReusableView
final class HeaderCollectionReusableView: UICollectionReusableView {
    
    static var toString: String {
        return String(describing: self)
    }
    static let id = HeaderCollectionReusableView.toString
    
    private let label: UILabel = {
        let label = UILabel()
        label.text = "header"
        label.font = .systemFont(ofSize: 50)
        label.textAlignment = .center
        label.textColor = .white
        return label
    }()
    
    func configure() {
        backgroundColor = .green
        addSubview(label)
    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
        label.frame = bounds
    }
    
}
```

そして、ViewControllerないで以下のように書いていきます。

cellを登録

```swift:ViewController
collectionView?.register(HeaderCollectionReusableView.self,
                                 forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader,
                                 withReuseIdentifier: HeaderCollectionReusableView.id)
```

`UICollectionViewDataSource`メソッド

```swift:ViewController
extension ViewController: UICollectionViewDataSource {
    
    func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
        let header = collectionView.dequeueReusableSupplementaryView(ofKind: UICollectionView.elementKindSectionHeader,
                                                                     withReuseIdentifier: HeaderCollectionReusableView.id,
                                                                     for: indexPath) as! HeaderCollectionReusableView
        header.configure()
        return header
    }
    
}
```

`UICollectionViewDelegateFlowLayout`メソッド

```swift:ViewController
extension ViewController: UICollectionViewDelegateFlowLayout {
    
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
        return CGSize(width: view.frame.size.width, height: 200)
    }

}
```

これで緑色のヘッダーがつかされたと思います。
青色のフッターも同じように作成します。

ただし、`UICollectionViewDataSource`の`dequeueReusableSupplementaryView`を以下のように変更します。

```swift:ViewController
extension ViewController: UICollectionViewDataSource {

    func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
        if kind == UICollectionView.elementKindSectionFooter {
            let footer = collectionView.dequeueReusableSupplementaryView(ofKind: UICollectionView.elementKindSectionFooter,
                                                                         withReuseIdentifier: FooterCollectionReusableView.id,
                                                                         for: indexPath) as! FooterCollectionReusableView
            footer.configure()
            return footer
        } else {
            let header = collectionView.dequeueReusableSupplementaryView(ofKind: UICollectionView.elementKindSectionHeader,
                                                                         withReuseIdentifier: HeaderCollectionReusableView.id,
                                                                         for: indexPath) as! HeaderCollectionReusableView
            header.configure()
            return header
        }
    }
    
}
```

最後に、以下のように`UICollectionViewDelegate`の`numberOfSections`を追加すれば完成です。

```swift:ViewController
extension ViewController: UICollectionViewDelegate {
    
    func numberOfSections(in collectionView: UICollectionView) -> Int {
        return 5
    }
    
}
```

#解説
大切なところだけ解説します。
[UICollectionReusableView](https://developer.apple.com/documentation/uikit/uicollectionreusableview)
UICollectionReusableViewでカスタムヘッダーやフッターを作成します。
カスタムヘッダーの手順は以下の通りです。
1.カスタムヘッダーを用意する
2.viewDidLoadでカスタムヘッダーをregisterする
3.collectionView（viewForSupplementaryElementOfKind）
4.collectionView（referenceSizeForHeaderInSection）

`viewForSupplementaryElementOfKind`ではヘッダーおよびフッターの設定をします。
`referenceSizeForHeaderInSection`では名前の通り、ヘッダーのサイズを決めます。


#おわりに
CollectionViewも奥が深いですね、、、