iOSのAutoLayoutの基本的な記述方法とエラーメッセージの種類
iOS 6にて導入されたAutoLayoutですが、iOS 7にて更に重要度が増し、いやがうえにも使用せざる終えなくなっている方も多いかと思います。
しかし、AutoLayoutは意外にわかりにくく、慣れが必要ではないかと思います。
そこで、備忘録を兼ねて少しAutoLayoutの基本的な記述方法とエラーの種類について記載したいと思います。
間違いがありましたならばご指摘ください。
ただし、私自身がStoryBoardを使わない派なので、ソースコードでの指定方法です(笑)
しかし、ソースコードでの記述方法を知るとStoryBoardでのAutoLayout指定の理解が深まるのではないかと思います。
加えて、ソースコードでの記述方法を知れば動的にAutoLayoutの変更ができる様になりますので、覚えておいて損は無いかと思います。
なお、UITableViewCellの様にAutoLayoutの使用を認めていないViewもありますので、注意してください。
– AutoLayoutの記述の基本 –
ソースでAutoLayoutを指定するには以下の事を行います。
- 追加するViewを作成する。
- AutoLayoutを使用する事を指定する。
- 親ViewにViewを追加する。
- AutoLayoutを設定する。
上記の事を1つでも間違えるとすぐにアプリが落ちるので注意が必要です。
それでは、順番に見ていく事にしましょう。
-追加するViewを作成する –
追加するViewの生成については、このエントリを読んでいる方は理解しているかと思いますが、以下の様な感じになるかと思います。
OriginalView *aView = [[OriginalView alloc] init];
※OriginalViewはUIViewを継承したクラスです。
– AutoLayoutを使用する事を指定する –
作成したViewにAutoLayoutを使用する事を指定します。
[aView setTranslatesAutoresizingMaskIntoConstraints:NO];
– 親ViewにViewを追加する-
これも説明は不要だとは思いますが、以下の様な感じになるかと思います。
なお、UIViewControllerのViewに追加する前提なので「self.view」はUIViewControllerのViewです。
[self.view addSubView:aView];
– AutoLayoutを設定する –
最後に一番重要なAutoLayoutの設定をします。
ここではわかりやすく、上下左右すべてを親Viewと同じにします。
※位置をずらしたい場合は適宜constant値を変更してください。
※同じ親Viewに追加されているViewであればtoItem値を別のViewにする事も可能です。
//AutoLayout設定を保持するArrayを用意 NSMutableArray *layoutConstraints = [NSMutableArray alloc] init]; //上 [layoutConstraints addObject:[NSLayoutConstraint constraintWithItem:aView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTop multiplier:1.0 constant:0.0]]; //下 [layoutConstraints addObject:[NSLayoutConstraint constraintWithItem:aView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0.0]]; //左 [layoutConstraints addObject:[NSLayoutConstraint constraintWithItem:aView attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeLeft multiplier:1.0 constant:0.0]]; //右 [layoutConstraints addObject:[NSLayoutConstraint constraintWithItem:aView attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeRight multiplier:1.0 constant:0.0]]; //親ViewにAutoLayout設定を追加する [self.view addConstraints:layoutConstraints];
設定内容の詳細は説明しませんが、NSLayoutConstraint@constraintWithItemメソッド使用時の注意点は以下の通りです。
これらの事を1つでも間違えるとすぐにアプリが落ちるので注意してください。
- 指定するViewは先にaddSubviewで追加されている必要がある。
- 2つのattribute引数で指定できる組み合わせは決まっている。(例:NSLayoutAttributeTopとNSLayoutAttributeBottomはOKだが、NSLayoutAttributeTopとNSLayoutAttributeLeftはNG等)
- 第一引数とtoItem引数で指定できるViewの順番は逆でも可能だが、統一しておいた方がわかりやすい。
- attribute引数で単純に横幅(NSLayoutAttributeWidth)や高さ(NSLayoutAttributeHeight)を指定する場合は、対になるViewはnilにする。
– AutoLayout設定時のエラーメッセージの種類 –
上記でも触れましたが、ソースでのAutoLayout指定は、少しでも間違えると該当箇所を実行した時にすぐにアプリを落としてくれます。
コンソールにエラーログが出ますが、意外にわかりにくいので、理解を深めるためにエラーの種類を記載しておきます。
勿論、アプリが落ちてうれしい人はそんなにはいないと思いますので、エラーを取る時の手助けになれば幸いです。
ここで取り上げるエラーの種類は以下の通りです。
- Viewを追加していない場合
- AutoLayoutを使用する指定をしていない場合
- NSLayoutConstraint@constraintWithItemメソッドのattribute引数の組み合わせ間違いの場合
– Viewを追加していない場合 –
Viewの追加(UIView@addSubview)をしていない時のエラーメッセージは以下の様な感じになります。
*** Terminating app due to uncaught exception 'NSGenericException', reason: 'Unable to install constraint on view. Does the constraint reference something from outside the subtree of the view? That's illegal. constraint: view:>' *** First throw call stack: (0x33a4b2a3 0x3b6c997f 0x33a4b1c5 0x34408ad5 0x35c8c3c1 0x35c8c535 0x358732e1 0x358735c7 0x3586de53 0x358557dd 0x358552c3 0x358c9ce3 0x358c9afb 0x358c6ceb 0x358c64c1 0x358b4b93 0x358b4833 0x2eed47 0x2e2eb9 0x2e6159 0x20b279 0x35868ab3 0x358dd8ef 0x35612c01 0x3bae04b7 0x3bae1dcb 0x33a1ef3b 0x33991ebd 0x33991d49 0x375442eb 0x358a7301 0xc4bc5 0x3bb00b20) libc++abi.dylib: terminate called throwing an exception
– AutoLayoutを使用する指定をしていない場合 –
UIView@setTranslatesAutoresizingMaskIntoConstraintsの指定忘れをした時のエラーメッセージは以下の様な感じになります。
Unable to simultaneously satisfy constraints. Probably at least one of the constraints in the following list is one you don't want. Try this: (1) look at each constraint and try to figure out which you don't expect; (2) find the code that added the unwanted constraint or constraints and fix it. (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints) ( "", "", "", "", "", "", "", "" ) Will attempt to recover by breaking constraint Break on objc_exception_throw to catch this in the debugger. The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful. 2013-10-28 07:15:57.038 (ApplicationName)[1269:907] Unable to simultaneously satisfy constraints. Probably at least one of the constraints in the following list is one you don't want. Try this: (1) look at each constraint and try to figure out which you don't expect; (2) find the code that added the unwanted constraint or constraints and fix it. (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints) ( "", "", "", "", "", "", "", "" ) Will attempt to recover by breaking constraint Break on objc_exception_throw to catch this in the debugger. The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.
– NSLayoutConstraint@constraintWithItemメソッドのattribute引数の組み合わせ間違いの場合 –
NSLayoutConstraint@constraintWithItemメソッドのattribute引数の組み合わせが不正の時のエラーメッセージは以下の様な感じになります。
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** +[NSLayoutConstraint constraintWithItem:attribute:relatedBy:toItem:attribute:multiplier:constant:]: Invalid pairing of layout attributes' *** First throw call stack: (0x33a4b2a3 0x3b6c997f 0x33a4b1c5 0x34409e77 0x2080f9 0x20427b 0x35872595 0x358c714b 0x358c7091 0x358c6f75 0x358c6e99 0x358c65d9 0x358c64c1 0x358b4b93 0x358b4833 0x3d5d47 0x3c9eb9 0x3cd159 0x2f2279 0x35868ab3 0x358dd8ef 0x35612c01 0x3bae04b7 0x3bae1dcb 0x33a1ef3b 0x33991ebd 0x33991d49 0x375442eb 0x358a7301 0x1abb15 0x3bb00b20) libc++abi.dylib: terminate called throwing an exception
– まとめ –
まだAutoLayoutを理解する上では覚えるべき事が残っていますが、ある程度の流れは掴めたかと思います。
ソースコードで記述する場合、Viewの配置をする時に手間はかかりますが、動的にAutoLayout設定を変更できたりするので、色々と使い道があるかと思います。
動的に変更する場合は、UIView@addConstraintsで指定した値をUIView@removeConstraintsで削除してから追加し直す等少し手間がかかりますが、上記の様な指定方法を理解していればそれ程難しい事ではないかと思います。
※削除する際には元のNSLayoutConstraintが必要になりますので、UIView@addConstraintsで使用したNSArrayをインスタンス変数にする等して残しておく必要があります。
なお、AutoLayoutを指定していてもUIView.frameプロパティで簡易的に位置が変更できる/できてしまうので、注意してください。
加えて、AutoLayoutをソースコードで指定する方法には、他にもアスキーアートでの指定方法があります。こちらは、新たに特殊な記述方法を覚えなくてはいけませんし、何よりも覚えても使える機能に制限があるので、覚えるのは無駄かも知れません。
ここに記載されている内容でAutoLayoutの理解が深まり、エラー取りの手助けになれば幸いです。