2列中央寄せのUIを実現する

# 完成図

<img src="https://qiita-image-store.s3.amazonaws.com/0/100736/559740f0-359e-b958-5fd0-ea50fb468a4b.png" width=60%>

UICollectionViewを使って実現しています。サンプルコードはこちらになります。
https://github.com/akatsuki174/CenteredLayoutCollectionView

# 2列に表示するまで

まずは適当にUICollectionViewでカスタムセルを使ってダミーデータを表示させるところまでやります。カスタムセルにはUILabelを貼ってあるだけです。
<img src="https://qiita-image-store.s3.amazonaws.com/0/100736/430ec0d4-d62b-dbb1-2093-754193c4cd8a.png" width=50%>

2列で表示させるためにUICollectionViewDelegateFlowLayoutを使います。このプロトコルの中の`func collectionView(UICollectionView, layout: UICollectionViewLayout, sizeForItemAt: IndexPath)`を使うことによってセルの縦横のサイズを指定することができます。
このメソッド内で画面サイズ÷2をして、そこからマージン分を引いてセルのサイズを指定します。

```swift
extension ViewController: UICollectionViewDelegateFlowLayout {
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        return CGSize(width: collectionView.bounds.width / 2 - 20, height: 40.0)
    }    
}
```

これでviewDidLoadで`collectionView.delegate = self`を付け足せば2列で表示されるようになります。

<img src="https://qiita-image-store.s3.amazonaws.com/0/100736/dcc2a1d0-fab8-47b2-f82c-cc6ee31a0661.png" width=50%>

# 文字を中央寄せにする

ポイントとしては制約とそれを設定するタイミングになります。

## 制約

まずカスタムセルの制約を次の通りにします。
![スクリーンショット 2017-07-02 9.06.15.png](https://qiita-image-store.s3.amazonaws.com/0/100736/1c800cb2-e8f3-1441-36ac-b57e51e4d76d.png)
leadingとtrailingをマージン0で設定します。ただしこのままだと横幅いっぱいにラベルが広がってしまうのでActiveフラグの切り替えを行います。ひとまずどちらか1つの制約をinActiveにします。storyboard上でActiveフラグを切り替えたい時は赤枠で囲っているinstalledのチェックを外します。そうするとActiveになっていない制約は薄い青色になります。

コード上ではカスタムセルクラスに以下のコードを書いてActiveフラグの切り替えを行います。これをすることによって左側のセルならleadingの制約がなくなってtrailingのマージン0という制約だけが機能し、右側のセルではその逆の現象が起こります。

```swift
func setupAlignment(index: Int) {
    if index % 2 == 0 { // 左側のセル
        leadingConstraint.isActive = false
        trailingConstraint.isActive = true
    } else { // 右側のセル
        leadingConstraint.isActive = true
        trailingConstraint.isActive = false
    }
}
```

これだけでいけるかなーと思いきや、この状態で実行するとこのようになります。
<img src="https://qiita-image-store.s3.amazonaws.com/0/100736/f5bcd6d0-e568-ef6e-4eb2-c125d52a73cc.png" width=50%>

## 制約を呼ぶタイミング

スクロールしているうちに想定通りのラベルサイズに直ったのでActiveフラグを切り替えているメソッドを呼ぶタイミングを`cellForItemAt`から`willDisplay`にずらしてみます。

```swift
func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
    if let cell = cell as? CustomCell {
        cell.setupAlignment(index: indexPath.row)
    }
}
```

するとこのような想定通りの表示になります。
<img src="https://qiita-image-store.s3.amazonaws.com/0/100736/3293fefc-4185-1585-9a50-e35e24fe57d3.png" width=50%>

# コード

xibなどはGitHubを見ていただけると。

```swift:ViewController.swift
class ViewController: UIViewController {

    @IBOutlet weak var collectionView: UICollectionView!
    let items = ["ああああああああ", "いいいいいい", "う", "ええええ", "おお", "かかかか", "ききき", "くくくくくく", "け", "こ", "さささささささ", "ししししししし", "すすすすすすす", "せせせ", "そそ", "たたた", "ちち", "つつつつつつつ", "ててててて", "と", "ななななななななななな", "にに", "ぬぬ", "ねねねねね", "ののの", "は", "ひひひ", "ふふふふふふふ", "へへへへへ", "ほほほ"]
    
    override func viewDidLoad() {
        super.viewDidLoad()
        collectionView.register(UINib(nibName: "CustomCell", bundle: nil), forCellWithReuseIdentifier: "CustomCell")
        self.collectionView.dataSource = self
        self.collectionView.delegate = self
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

}

extension ViewController: UICollectionViewDataSource {
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return items.count
    }
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CustomCell", for: indexPath) as! CustomCell
        cell.keywordLabel.text = items[indexPath.row]
        cell.keywordLabel.backgroundColor = UIColor.gray
        return cell
    }
    
    func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
        if let cell = cell as? CustomCell {
            cell.setupAlignment(index: indexPath.row)
        }
    }

}

extension ViewController: UICollectionViewDelegateFlowLayout {
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        return CGSize(width: collectionView.bounds.width / 2 - 10, height: 40.0)
    }
    
}
```

```swift:CustomCell.swift
class CustomCell: UICollectionViewCell {
    
    @IBOutlet weak var keywordLabel: UILabel!    
    @IBOutlet weak var trailingConstraint: NSLayoutConstraint!
    @IBOutlet weak var leadingConstraint: NSLayoutConstraint!
    
    override func awakeFromNib() {
        super.awakeFromNib()
    }

    func setupAlignment(index: Int) {
        if index % 2 == 0 { // 左側のセル
            leadingConstraint.isActive = false
            trailingConstraint.isActive = true
        } else { // 右側のセル
            leadingConstraint.isActive = true
            trailingConstraint.isActive = false
        }
    }

}
```


# おまけ

■セルUIカスタマイズ

一番最初に貼り付けた画像のようにinsetがあり丸みを帯びたラベルを作成してみます。

丸くする部分等は以下のコードで実現します。

```swift
func configureCell() {
    keywordLabel.backgroundColor = UIColor.gray
    keywordLabel.layer.cornerRadius = 10
    keywordLabel.layer.borderColor = UIColor.black.cgColor
    keywordLabel.layer.borderWidth = 1.0
    keywordLabel.layer.masksToBounds = true
    keywordLabel.adjustsFontSizeToFitWidth = true
}
```

<img src="https://qiita-image-store.s3.amazonaws.com/0/100736/43943bf3-5778-f166-3aca-ecfe49c245af.png" width=50%>

insetの調整に関しては専用のクラスを作ります。

```swift
class PaddingLabel : UILabel {
    var insets = UIEdgeInsetsMake(0, 0, 0, 0)
    
    override func drawText(in rect: CGRect) {
        super.drawText(in: UIEdgeInsetsInsetRect(rect, insets))
    }
    
    override var intrinsicContentSize: CGSize {
        var contentSize = super.intrinsicContentSize
        contentSize.height += insets.top + insets.bottom
        contentSize.width += insets.left + insets.right
        return contentSize
    }
}
```

keywordLabelをUILabelからこのPaddingLabelに変更した上でセルのUIを調整する時に（`configureCell`のメソッド内で）以下のコードを追加すればinsetが確保できます。

```swift
keywordLabel.insets = UIEdgeInsets(top: 5, left: 10, bottom: 5, right: 10)
```

その他文字数が多い時の対応、Collection View自体のマージンの設定などもGitHub上では設定しています。