Auto Layoutメモ
Visual Format Language (視覚的書式言語)
Visual Format Language (VFL)を使ってみたので、メモしておく。先に感想を言うと、慣れれば楽なのかもしれないが、慣れるまでが大変。慣れれば、サクっと書くには良いのかもしれないが、IB上でやったほうが楽。
シンボル
VFLで使用する主なシンボル
シンボル | 意味 |
H: | 水平方向 |
V: | 垂直方向 |
| | 親ビュー |
- | ビューとビューの連結 |
VFL例1
横:200ポイント 縦:100ポイントのビュー(view)を親ヴューの左上に配置する場合。
// viewDidLoad内に記述 UIView *view = UIView.new; view.backgroundColor = [UIColor redColor]; // AutoresizingMaskを使用しない //(これはAuto Layoutを使用するときには必須の設定) view.translatesAutoresizingMaskIntoConstraints = NO; [self.view addSubview:view] // 水平方向の制約 NSString *horizontal = @"H:|-[view(==200)]"; // 垂直方向の制約 NSString *vertical = @"V:|-[view(==100)]" // VFLで使用するキーと変数をバインドする // NSDictionaryOfVariableBindingsで@{@"view":view}が生成される NSDictionary *views = NSDictionaryOfVariableBindings(view); // 水平方向の制約を親ビューに追加する [self.view addConstraints: [NSLayoutConstraint constraintsWithVisualFormat:horizontal options:0 metrics:nil views:views]]; // 垂直方向の制約を親ビューに追加する [self.view addConstraints: [NSLayoutConstraint constraintsWithVisualFormat:vertical options:0 metrics:nil views:views]];
H:|-[view(==200)]は
- H: 水平方向の制約
- |-[view(==200)] 親ビュー(|)とviewとの連結。-でAqua標準間隔を表す。
- (==200) で水平方向の場合、viewの横幅を設定する
- (==200)のイコール部分は省略して[view(200)]と書くことができる
V:|-[view(==100)]に関しても同じ感じ。
Aqua標準間隔について
StackOverflowによると同じレイヤー上にあるビューとビューとの間隔は8ポイント、ビューとその親ビューとの間隔は20ポイントになるようだ。
metrics引数
横幅200とか縦幅100の部分はkey-valueを使用して、 constraintsWithVisualFormat:options:metrics:views:のmetrics引数に渡すことができる。
以下のような感じ。
NSString *horizontal = @"H:|-[view(width)]"; NSString *vertical = @"V:|-[view(height)]"; NSDictionary *metrics = @{@"width":@200, @"height":@100}; // 水平方向の制約 [self.view addConstraints: [NSLayoutConstraint constraintsWithVisualFormat:horizontal options:0 metrics:metrics views:views]];
VFL例2
同じ幅のビューを2つ並べる。
// 左に配置するビュー UIView *leftView = UIView.new; leftView.backgroundColor = [UIColor redColor]; leftView.translatesAutoresizingMaskIntoConstraints = NO; [self.view addSubview:leftView]; // 右に配置するビュー UIView *rightView = UIView.new; rightView.backgroundColor = [UIColor blueColor]; rightView.translatesAutoresizingMaskIntoConstraints = NO; [self.view addSubview:rightView]; // 水平方向の制約 NSString *horizontal = @"H:|-[leftView]-[rightView(leftView)]-|"; // 左のビューの垂直方向の制約 NSString *leftVertical = @"V:|-topMargin-[leftView(height)]"; // 右のビューの垂直方向の制約 NSString *rightVertical = @"V:|-topMargin-[rightView(leftView)]"; NSDictionary *metrics = @{@"topMargin":@20, @"height":@100}; NSDictionary *views = NSDictionaryOfVariableBindings(leftView, rightView); [self.view addConstraints: [NSLayoutConstraint constraintsWithVisualFormat:horizontal options:0 metrics:metrics views:views]]; [self.view addConstraints: [NSLayoutConstraint constraintsWithVisualFormat:leftVertical options:0 metrics:metrics views:views]]; [self.view addConstraints: [NSLayoutConstraint constraintsWithVisualFormat:rightVertical options:0 metrics:metrics views:views]];
Auto Layoutを使う時、気をつける点は
- 動的にビューを生成した場合はtranslatesAutoresizingMaskIntoConstraintsをNOに設定する
- 親ビューにaddSubviewしてから制約(constraint)を設定する
- IBで配置したビューにプログラムで制約をつけるときは、IB上の制約をビルド時に削除する(Placeholder Remove at build time)にチェックを入れる
- VFLではできなかったり、やりづらいレイアウトのときは、IBかconstraintWithItem:attribute:relatedBy:toItem:attribute:multiplier:constantのメソッドを使う