【Xcode10.0&Swift4.2】UICollectionViewの使い方

# はじめに
今回はUICollectionViewを使って、iOS版slackのリアクションスタンプを表示する画面、っぽい奴を作ります。
スタンプはUnicodeで文字として表示します(画像リソースとして扱うよりも良いかと)

![Simulator Screen Shot - iPhone XR - 2018-10-06 at 17.25.00.png](https://qiita-image-store.s3.amazonaws.com/0/279881/034656c2-ce87-a627-04cf-023c6ab2328f.png)

## 開発環境
* macOS 10.13.6
* Xcode10
* Swift 4.2

## Storyboard
まずはStoryboardでViewControllerにUICollectionViewを配置します。
Xcode10からオブジェクトの選択がナビゲーション上のボタンに変わったのは最初混乱しました。
<img width="857" alt="スクリーンショット 2018-10-06 16.52.14.png" src="https://qiita-image-store.s3.amazonaws.com/0/279881/2d0138d5-3319-1ccb-e3a9-809e025a85fa.png">
検索して

<img width="850" alt="スクリーンショット 2018-10-06 16.58.01.png" src="https://qiita-image-store.s3.amazonaws.com/0/279881/43f9f95c-1f56-4315-d887-79880ef9743d.png">
CollectionViewを置いて

<img width="324" alt="スクリーンショット 2018-10-06 16.58.16.png" src="https://qiita-image-store.s3.amazonaws.com/0/279881/80191b17-a1c5-821c-8164-445fd1adf7c1.png">
制約を四方全て0にすればおkです。

## CollectionViewCell
xibでCellを作ってもいいのですが、スタンプを表示するだけなので今配置したCollectinoView内で完結させます。
CollectionViewの中にCellが内包されているので、そこにUILabelを配置します。
<img width="483" alt="スクリーンショット 2018-10-06 17.02.38.png" src="https://qiita-image-store.s3.amazonaws.com/0/279881/a91acefb-ace4-ea7e-bdc6-4fa545eabc58.png">
UILabelを置いて

<img width="262" alt="スクリーンショット 2018-10-06 17.05.47.png" src="https://qiita-image-store.s3.amazonaws.com/0/279881/c440f0e1-a938-81d0-3c0b-2ef8ff81ca6f.png">
UILabelのtitleに😀を入力し、中央揃えにします。

<img width="259" alt="スクリーンショット 2018-10-06 17.07.19.png" src="https://qiita-image-store.s3.amazonaws.com/0/279881/caeb6ca4-faa8-655b-7305-fdc13880ddfe.png">
ViewControllerからCellのUILabelを参照するためにTagを指定します。

<img width="520" alt="スクリーンショット 2018-10-06 17.05.54.png" src="https://qiita-image-store.s3.amazonaws.com/0/279881/a6d1f9be-3f2c-84d4-fb58-a5697b6b077e.png">
ViewControllerで見るとこんな感じです。

<img width="341" alt="スクリーンショット 2018-10-06 17.23.52.png" src="https://qiita-image-store.s3.amazonaws.com/0/279881/4f6d0ce9-a9c9-f3cc-8972-26907f687284.png">
Cellを再利用するためにIDも設定しておきます。

<img width="1130" alt="スクリーンショット 2018-10-06 17.08.48.png" src="https://qiita-image-store.s3.amazonaws.com/0/279881/0db8ede8-46d6-8d3f-1a39-7ed87cebd46f.png">
最後にViewControllerとUICollectionViewをアウトレット接続すればStoryboard上の作業は完了です！

## ViewController
まずは表示するスタンプの定義と、CollectionViewのDelegate&DataSourceの紐付けを忘れないうちにやっておきましょう。


```swift:ViewController.swift
import UIKit

class ViewController: UIViewController {
    @IBOutlet weak var collectionView: UICollectionView!
    // スタンプの定義(Unicode)
    let stamps = ["1F600", "1F601", "1F602", "1F603", "1F604", "1F605", "1F606", "1F606",
 "1F607", "1F608", "1F609", "1F60A", "1F60B", "1F60C", "1F60D", "1F60E", "1F60F",
 "1F610", "1F611", "1F612", "1F613", "1F614", "1F615", "1F616", "1F617", "1F618",
 "1F619", "1F61A", "1F61B", "1F61C", "1F61D", "1F61E", "1F61F"]
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // DelegateとDataSourceの紐付け
        self.collectionView.delegate = self
        self.collectionView.dataSource = self
    }
}
```

そしたらDelegateとDataSourceのプロトコルを実装します。
今回はタップして何かする的な処理は書かないので、Delegateは良しなにやってください。

```swift:ViewController.swift
extension ViewController: UICollectionViewDelegate {
    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        // スタンプが押された時の処理を書く
    }
}

extension ViewController: UICollectionViewDataSource {
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return self.stamps.count
    }
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath)
        if let label = cell.contentView.viewWithTag(1) as? UILabel {
            // CollectionViewCellのUILabelを取得し、絵文字をに代入する
            let text = UnicodeScalar(Int(self.stamps[indexPath.row], radix: 16)!)
            label.text = text?.description
        }
        
        return cell
    }
}
```

ViewController側の処理はこれだけです。
Unicodeの変換処理が入っているので若干のロジックが組み込まれていますが、UILabelに文字を表示するだけならさらにソースが減ります。

```swift:ViewController.swift
extension ViewController: UICollectionViewDataSource {
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return self.stamps.count
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath)
        if let label = cell.contentView.viewWithTag(1) as? UILabel {
            // 文字列を代入
            label.text = "hogehoge"
        }

        return cell
    }
}
```

## 終わりに
以上でUICollectionViewを使って、iOS版slackのリアクションスタンプを表示する画面っぽい奴が作れました。UICollectionViewもCellのレイアウトを考えなければかなり簡単に使用することができます。
Cell間のマージンやら一行に表示する要素数やらは良しなにコントロールしてくれるのも魅力ですね。