役に立つかどうかよくわからないTipsシリーズ
storyboard や xib で AutoLayout として設定する時に
大事なのは「Constraint」
レイアウト制約です
objective-c 時代から苦手な人も多いようで
一番最初は自分も戸惑いが大きかったですが
慣れてみるとこんなに便利なものはありません
本来であれば、IB上ですべて済ませられれば理想的ですが
動的にビューを生成したりするときには
プログラマブルに書いていく必要があります
NSLayoutConstraint
を生成するのは、2通りのやり方があります
ここでの例は
「hogeView
というViewを、self.view
の上部にぴったり44pxの高さで配置する」
(ここでいうself
はViewControllerとする)
という表示を期待しています
1.引数たっぷりのコンストラクタで作る
self.view.addConstraints(
[
NSLayoutConstraint(
item: hogeView,
attribute: .Top,
relatedBy: .Equal,
toItem: self.view,
attribute: .Top,
multiplier: 1.0,
constant: 0
),
NSLayoutConstraint(
item: hogeView,
attribute: .Leading,
relatedBy: .Equal,
toItem: self.view,
attribute: .Leading,
multiplier: 1.0,
constant: 0
),
NSLayoutConstraint(
item: hogeView,
attribute: .Trailing,
relatedBy: .Equal,
toItem: self.view,
attribute: .Trailing,
multiplier: 1.0,
constant: 0
),
NSLayoutConstraint(
item: hogeView,
attribute: .Height,
relatedBy: .Equal,
toItem: nil,
attribute: .Height,
multiplier: 1.0,
constant: 44.0
),
]
)
2.規定の文字列を渡すコンストラクタで作る
let views = ["hoge": hogeView]
self.view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat(
"H:|-0-[hoge]-0-|",
options: NSLayoutFormatOptions(),
metrics: nil,
views: views
)
)
self.view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat(
"V:|-0-[hoge(44)]",
options: NSLayoutFormatOptions(),
metrics: nil,
views: views
)
)
まぁ、この辺は好みなのですが、後者はどうにも好きになれません
上の例では1つのビューが対象なのでシンプルですが、
複数のビューが複雑に絡みだすと
メンテナンスするときにわかりづらいし、なおしづらいからです
しかしながら、前者の引数たっぷりのコンストラクタは
ソースが冗長になりすぎます
なので、このような関数をトップレベルに作ると便利になります
/// 制約(NSLayoutConstraint)を生成する
/// - parameter item: 制約を追加するオブジェクト
/// - parameter attr: 制約を追加するオブジェクトに与える属性
/// - parameter to: 制約の相手
/// - parameter attrTo: 制約相手に使用する属性
/// - parameter constant: 定数値
/// - parameter multiplier: 乗数値
/// - parameter relate: 計算式の関係性
/// - parameter priority: 制約の優先度
/// - returns: 制約(NSLayoutConstraint)オブジェクト
public func Constraint(item: AnyObject, _ attr: NSLayoutAttribute, to: AnyObject?, _ attrTo: NSLayoutAttribute, constant: CGFloat = 0.0, multiplier: CGFloat = 1.0, relate: NSLayoutRelation = .Equal, priority: UILayoutPriority = UILayoutPriorityRequired) -> NSLayoutConstraint {
let ret = NSLayoutConstraint(
item: item,
attribute: attr,
relatedBy: relate,
toItem: to,
attribute: attrTo,
multiplier: multiplier,
constant: constant
)
ret.priority = priority
return ret
}
「うわっ、なにこれ? 引数たっぷりじゃん」
ってなりましたか?
しかしながら、引数constant
以降はすべて省略可能な引数です
IB上で AutoLayout を触る時を想定したときに
それほど変更することが少ないものは省略可能としておくことで、書くことを少なくしています
必要なものだけ引数に追加するイメージですね
さらに、属性をあらわすNSLayoutAttribute
用の引数 attr
とattrTo
はメソッドラベルを省けるようにしています。
どうせ制約対象のitem
もしくはto
の属性は必要なんだから・・・という考え方です
これにより、下記のようにソースを書くことができます
self.view.addConstraints([
Constraint(hogeView, .Top, to: self.view, .Top),
Constraint(hogeView, .Bottom, to: self.view, .Bottom),
Constraint(hogeView, .Left, to: self.view, .Left),
Constraint(hogeView, .Width, to: nil, .Width, constant: 44),
])
これで例と同じ表示をしてくれるようになります
シンプルになりましたね
IBでピタピタと制約を貼っていくのと、それほど変わらず直感的で労力少なめに出来る気がしませんか?