Autolayout and Orientation

Autolayoutは便利。

特にInterfaceBuilderで設定する場合は。

 

コード側で設定する時も、あの文法さえ理解すればそんなに難しくはない。

最初はとっつきにくく感じるけど、結局は慣れの問題。何だってそうか。


でも、デバイスの縦と横とでレイアウトを大幅に変更したい時は少々、手を加える必要がある。

親のviewに対して絶対座標で常に指定できるのであれば、

デバイスの向きに関わらず値を調整するだけで済むけれど

各UIの要素に対して相対的な位置で並べる時はそうもいかない。

 

例えば、こんなレイアウト。

縦と横とで画像とlabelの位置関係が異なるため、Autolayoutも縦用と横用とを用意する必要がある。

その処理はUIViewControllerの - (void)updateViewConstraints の中に書く。

以下コード(label2の文字列が1行で収まらないことも考慮)。

 

- (void)updateViewConstraints
{
    [super updateViewConstraints];

    // remove first
    [self.view removeConstraints:self.view.constraints];
    
    if (UIInterfaceOrientationIsLandscape(self.interfaceOrientation)) {
        // for landscape
        [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-25-[_label1(21)]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(_label1)]];
        [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-15-[_label1]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(_label1)]];
        
        [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[_label1]-10-[_imageView(240)]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(_label1, _imageView)]];
        [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-15-[_imageView(240)]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(_label1, _imageView)]];
        
        [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:[_imageView]-15-[_label2(220)]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(_label2, _imageView)]];
        [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[_label1]-10-[_label2(<=150)]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(_label2, _label1)]];
        
        [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:[_imageView]-15-[_label3]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(_label3, _imageView)]];
        [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[_label2]-15-[_label3(21)]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(_label2, _label3)]];

    } else {
        // for portrait
        [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-30-[_label1(21)]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(_label1)]];
        [self.view addConstraint:[NSLayoutConstraint constraintWithItem:_label1 attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0]];
        
        [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[_label1]-15-[_imageView(240)]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(_label1, _imageView)]];
        [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:[_imageView(240)]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(_imageView)]];
        [self.view addConstraint:[NSLayoutConstraint constraintWithItem:_imageView attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0]];
        
        [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[_imageView]-15-[_label2(<=150)]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(_label2, _imageView)]];
        [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:[_label2(290)]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(_label2)]];
        [self.view addConstraint:[NSLayoutConstraint constraintWithItem:_label2 attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0]];
        
        [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[_label2]-15-[_label3(21)]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(_label2, _label3)]];
        [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:[_label3(290)]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(_label3)]];
        [self.view addConstraint:[NSLayoutConstraint constraintWithItem:_label3 attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0]];   
    }
}

 

これで縦と横とでちゃんとレイアウトが保たれる。
旧来通りの矩形計算と比べ、手間的にはそんなに変わらない気もするけれど

文字列の長さを計算したりする必要がないので、楽になったことには違いない。


堕落プログラマにはなれないものの、ものぐさプログラマにはなれる、

Autolayoutとはそんな機能、かもしれなかった。