タコさんブログ

プログラミングメモと小言

Auto Layoutメモ

Visual Format Language (視覚的書式言語)

Visual Format Language (VFL)を使ってみたので、メモしておく。先に感想を言うと、慣れれば楽なのかもしれないが、慣れるまでが大変。慣れれば、サクっと書くには良いのかもしれないが、IB上でやったほうが楽。

シンボル

VFLで使用する主なシンボル

シンボル 意味
H: 水平方向
V: 垂直方向
| 親ビュー
- ビューとビューの連結

VFL例1

横:200ポイント 縦:100ポイントのビュー(view)を親ヴューの左上に配置する場合。
f:id:tiny_wing:20141026010837p:plain

// 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つ並べる。
f:id:tiny_wing:20141026010841p:plain

// 左に配置するビュー
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のメソッドを使う