コードでAutolayout

以前からAutolayoutの重要性や便利さをちらちら目にしてきましたがとっつきにくさからずっと避けてました。
そろそろ身につけなきゃとうことでレシピをまとめたいと思います。

## 参考
http://www.slideshare.net/classmethod/i-os-auto-layout
を参考にさせて頂きました。

## Autolayoutとは
AutolayoutとはviewにConstraint（制約）を付けることでレイアウトする方法。
各view同士を5px間隔で配置する、など画面の大きさにとらわれず最適なviewの配置をします。
制約は`NSLayoutConstraint`クラスによって定義でき、制約には優先度を設定できます。

## `NSLayoutConstraint`
`NSLayoutConstraint`は2つのコンストラクタがあります。

### `constraintsWithVisualFormat:options:metrics:views`
こっちの方が複数のviewの制約を一度に定義できるので便利そう。
だが、`visualFormat`の書き方がとっつきにくいのでAutolayoutについて理解が深まってから。
例えば`@"V:|-8-[button1]"`みたいにV（縦）方向の定義で
「上8px隙間を開けてbutton1を配置する」といった具合。
今回はこちらは使わない

### `constraintWithItem:attribute:relatedBy:toItem:attribute:multiplier:constant:`
こちらは1つのviewに対して制約を定義していく。
`item`と`toItem`に対して制約を定義して他の引数で制約を調整する。
今回はこっちを使ってNSLayoutConstraintの使い方を学んでいく。

| arg | description |
|:----|------------:|
| item | 制約を追加するview、このviewに対して第2引数の`attribute`で指定した属性を反映させる |
| attribute | 属性 |
| relateBy | 計算式の関係性 |
| toItem | 位置計算に使用するview |
| attribute | 位置計算に使用する属性、値の取得元は`toItem` |
| multiplier | 乗算値 |
| constant | 定数値 |

## 制約
制約は`NSLayoutConstraint`でview同士やviewに対して制約を生成して親viewに`addConstraints`していく。
`viewController`に子viewの`aView`があるとすると

```
       self.view.addConstraints([
            
            NSLayoutConstraint(
                item: self.aView,
                attribute: NSLayoutAttribute.Top,
                relatedBy: NSLayoutRelation.Equal,
                toItem: self.view,
                attribute: NSLayoutAttribute.Top,
                multiplier: 1.0,
                constant: 0
            )]
        )
```

のように`self.view`に子viewである`self.aView`についての制約を追加していく

### 制約を考える上で
制約とは計算式で表されているみたい。
例えば「view1の右端から右に10pxの位置にview2の左端が位置する」ってのを書きたいとき

```objc
view2.left = view1.right * 1 + 10

(item).(attribute1) (relatedBy) (toItem).(attribute2) * (multiplier) + (constant)
```
`relatedBy`は`=`を表す。`NSLayoutRelation.Equal`みたいな。

となる。これを想像しながら制約を作っていくとイメージしやすそう

## コードレシピ
コード書いてみないと覚えらんないので色んな制約を試してみました。

### 画面上部に引っ付いている、横幅いっぱいのnavigatoinView

```objc
        self.navigationView.setTranslatesAutoresizingMaskIntoConstraints(false)

        self.view.addConstraints([
            
            // self.veiwの上から0pxの位置に配置
            NSLayoutConstraint(
                item: self.navigationView,
                attribute: NSLayoutAttribute.Top,
                relatedBy: NSLayoutRelation.Equal,
                toItem: self.view,
                attribute: NSLayoutAttribute.Top,
                multiplier: 1.0,
                constant: 0
            ),
            
            // self.viewの横幅いっぱいにする
            NSLayoutConstraint(
                item: self.navigationView,
                attribute: NSLayoutAttribute.Width,
                relatedBy: NSLayoutRelation.Equal,
                toItem: self.view,
                attribute: NSLayoutAttribute.Width,
                multiplier: 1.0,
                constant: 0
            ),
            
            // self.viewのレイアウトに関わらず高さは64px
            NSLayoutConstraint(
                item: self.navigationView,
                attribute: NSLayoutAttribute.Height,
                relatedBy: NSLayoutRelation.Equal,
                toItem: nil,
                attribute: NSLayoutAttribute.Height,
                multiplier: 1.0,
                constant: 64
            )]
        )
```

### navigationViewの上から10px左から10pxの位置にあり、縦横44pxのleftButton

```objc
        self.leftButton.setTranslatesAutoresizingMaskIntoConstraints(false)

        self.navigationView.addConstraints([
            
            // 上から10px
            NSLayoutConstraint(
                item: self.leftButton,
                attribute: .Top,
                relatedBy: .Equal,
                toItem: self.navigationView,
                attribute: .Top,
                multiplier: 1.0,
                constant: 10
            ),
            
            // 左から10px
            NSLayoutConstraint(
                item: self.leftButton,
                attribute: .Left,
                relatedBy: .Equal,
                toItem: self.navigationView,
                attribute: .Left,
                multiplier: 1.0,
                constant: 10
            ),
            
            // 横（固定）
            NSLayoutConstraint(
                item: self.leftButton,
                attribute: .Width,
                relatedBy: .Equal,
                toItem: nil,
                attribute: .Width,
                multiplier: 1.0,
                constant: 44
            ),
            
            // 縦（固定）
            NSLayoutConstraint(
                item: self.leftButton,
                attribute: .Height,
                relatedBy: .Equal,
                toItem: nil,
                attribute: .Height,
                multiplier: 1.0,
                constant: 44
            )]
        )
```

### navigationViewの中央にある、横幅がnavigationViewの横幅によって動的に変化するcenterView

横幅320pxの時、navigationView.width:320px、centerView.width:100pxの比率を保ような横幅

```objc
        self.centerView.setTranslatesAutoresizingMaskIntoConstraints(false)

        self.navigationView.addConstraints([
            
            // centerViewのcenter.xをnavigationViewと同じに
            NSLayoutConstraint(
                item: self.centerView,
                attribute: .CenterX,
                relatedBy: .Equal,
                toItem: self.navigationView,
                attribute: .CenterX,
                multiplier: 1.0,
                constant: 0
            ),
            
            // centerViewのcenter.yをnavigationViewと同じに
            NSLayoutConstraint(
                item: self.centerView,
                attribute: .CenterY,
                relatedBy: .Equal,
                toItem: self.navigationView,
                attribute: .CenterY,
                multiplier: 1.0,
                constant: 0
            ),
            
            // navigationView.width:320のときcenterView:100の比率
            NSLayoutConstraint(
                item: self.centerView,
                attribute: .Width,
                relatedBy: .Equal,
                toItem: self.navigationView,
                attribute: .Width,
                multiplier: 100.0 / 320.0,
                constant: 0
            ),
            
            // 縦は44pxで固定
            NSLayoutConstraint(
                item: self.centerView,
                attribute: .Height,
                relatedBy: .Equal,
                toItem: nil,
                attribute: .Height,
                multiplier: 1.0,
                constant: 44
            )]
        )

```

### centerViewの右から20pxのところに位置する縦横44pxのrightButton

```objc
        self.rightButton.setTranslatesAutoresizingMaskIntoConstraints(false)
        
        self.navigationView.addConstraints([
            
            // centerViewの右から20pxのところに配置
            NSLayoutConstraint(
                item: self.rightButton,
                attribute: .Left,
                relatedBy: .Equal,
                toItem: self.centerView,
                attribute: .Right,
                multiplier: 1.0,
                constant: 20
            ),
            
            // center.yはcenterViewと同じ
            NSLayoutConstraint(
                item: self.rightButton,
                attribute: .CenterY,
                relatedBy: .Equal,
                toItem: self.centerView,
                attribute: .CenterY,
                multiplier: 1.0,
                constant: 0
            ),
            
            // 横（固定）
            NSLayoutConstraint(
                item: self.rightButton,
                attribute: .Width,
                relatedBy: .Equal,
                toItem: nil,
                attribute: .Width,
                multiplier: 1.0,
                constant: 44
            ),
            
            // 縦（固定）
            NSLayoutConstraint(
                item: self.rightButton,
                attribute: .Height,
                relatedBy: .Equal,
                toItem: nil,
                attribute: .Height,
                multiplier: 1.0,
                constant: 44
            )]
        )
```

## おしまい
autolayoutの超基本を触れたのであとは深堀りをしていく。
このコードをロジックと同じクラスに書くと見通しが悪くなるのでレイアウトは別クラスにするとか設計を含めて学んでいきたい。

#### メモ
`NSLayoutRelation`の種類別
`NSLayoutAttribute`の`LeftMargin`とか
優先度の使い方
`constraintsWithVisualFormat:options:metrics:views`のこと