ios6 auto layout
Post on 04-Jun-2015
16.051 views
TRANSCRIPT
iOS6 Auto Layout
2012/12/10クラスメソッド かけがわ
自己紹介
アジェンダ• Auto Layout• Auto Layout の基礎知識• Interface Builder で Auto Layout を設定• ソースコードで Auto Layout を設定• Auto Layout 補足
Auto Layout の基礎知識
Auto Layout
• 「制約」ベースのレイアウトシステム
• Autosizing を置き換えるもの
• Mac アプリケーションでは、 OS X Lion で既に導入されている
Constraint
• レイアウトを決定するための「制約」
• 他の UI コンポーネントとの相対的な位置・サイズを定義
• 制約は NSLayoutConstraint クラスのインスタンスによって表現される
Auto Layout と Autosizing の違いAutosizing
• サブビューの親ビューに対する相対関係を指定する• 親ビューとの間のマージン• 親ビューに追従してリサイズするか
Auto Layout と Autosizing の違いAuto Layout
• レイアウト上のルールを制約として定義• サブビューの親ビューに対する相対位置• 兄弟ビューとの相対位置やサイズ• 自身のサイズ
• ルールは必ずしも厳密に満たされない• サイズや位置に関して、「 20px 以上」や
「 10px 以下」といった表現が可能• 優先順位
Leading & Trailing• アラビア語など、右側が文頭になる環境に対する、レイアウト上の
ローカライズを容易にするための機能
• Leading は文字列の先頭側、 Trailing は文字列の末尾側を指す
• 日本語や英語の環境では、 Leading は Left 、 Trailing は Right に対応する
• アラビア語など、右側が文頭になる環境では、 Leading がRight 、 Trailing が Left に対応する
• Left や Right の代わりに Leading や Trailing を利用しておくと、 OS の言語がアラビア語に設定されている環境ではレイアウトの位置が左右反転する
Leading & Trailing
OS の言語設定がアラビア語OS の言語設定が英語
親ビュー内でのボタンの水平方向のアライメントに関して、 Leading 側に寄せて 20px のスペースを置くという制約を追加した場合
Auto Layout の使い方
使い方使い方は2通り
• Interface Builder 上で制約を設定する• ソースコードで NSLayoutConstraint クラス
を使って設定する
Interface Builder で制約を設定する
Auto Layout の切り替え• ファイルインスペクタの Use
Autolayout を有効にする
• Use Autolayout を無効にすれば従来通り
• iOS5.x 以前で Use Autolayout を有効にするとクラッシュするので注意
Interface Builder 上のメニュー
Interface Builder 上のメニュー
Interface Builder 上のメニュー
コンポーネントのアライメントに関する制約を追加する操作
Interface Builder 上のメニュー
コンポーネントの相対的な位置やサイズを固定する制約を追加する操作
Interface Builder 上のメニュー
Interface Builder 上でコンポーネントをリサイズした場合に、周辺コンポーネントに既存の制約を適用して移動やリサイズなどを行うかを設定する
• Siblings and Ancestors親と兄弟に制約を適用する
• Descendants子に制約を適用する
Align – 端揃え• Left Edges
• 複数のコンポーネントの左端の水平位置を揃える制約を追加する• 追加される制約は Direction の設定による
• Right Edges• 複数のコンポーネントの右端の水平位置を揃える制約を追加する• 追加される制約は Direction の設定による
• Top Edges• 複数のコンポーネントの上端の垂直位置を揃える制約を追加する• 追加される制約は Top Alignment
• Bottom Edges• 複数のコンポーネントの下端の垂直位置を揃える制約を追加する• 追加される制約は Bottom Alignment
Align – 基準位置揃え• Horizontal Centers
• 複数のコンポーネントの水平方向の中心位置を揃える制約を追加する
• 追加される制約は Center X Alignment
• Vertical Centers• 複数のコンポーネントの垂直方向の中心位置を揃える制約を追加す
る• 追加される制約は Center Y Alignment
• Baselines• 複数のコンポーネントのベースライン位置関係を固定する制約を追
加する• 追加される制約は Baseline Alignment
Align – 親ビュー内でセンタリング
• Horizontal Center in Container• コンポーネントとその親コンテナの水平方向の中心位置
を揃える制約を追加する• 追加される制約は Center X Alignment
• Vertical Center in Container• コンポーネントとその親コンテナの垂直方向の中心位置
を揃える制約を追加する• 追加される制約は Center Y Alignment
Pin – サイズ• Width
• コンポーネントの幅に関する制約を追加する• 追加される制約は Width• 制約は対象コンポーネントに追加
• Height• コンポーネントの高さに関する制約を追加する• 追加される制約は Height• 制約は対象コンポーネントに追加
Pin – コンポーネント間の間隔• Horizontal Spacing
• 2つのコンポーネントの間の水平方向の距離に関する制約を追加する
• 追加される制約は Horizontal Space
• Vertical Spacing• 2つのコンポーネントの間の垂直方向の距離に関する制約
を追加する• 追加される制約は Vertical Space
Pin – 親ビューの端との間隔• Leading Space to SuperView
• コンポーネントの左端とその親ビューの左端の距離に関する制約を追加する• 追加される制約は Horizontal Space
• Trailing Space to SuperView• コンポーネントの右端とその親ビューの右端の距離に関する制約を追加する• 追加される制約は Horizontal Space
• Top Space to SuperView• コンポーネントの上端とその親ビューの上端の距離に関する制約を追加する• 追加される制約は Vertical Space
• Bottom Space to SuperView• コンポーネントの下端とその親ビューの下端の距離に関する制約を追加する• 追加される制約は Vertical Space
Pin – サイズの連動• Widths Equally
• 複数のコンポーネントの幅を等しくする制約を追加する• 追加される制約は Equal Widths
• Heights Equally• 複数のコンポーネントの高さを等しくする制約を追加す
る• 追加される制約は Equal Heights
Demo
制約の種類• アライメントに関する制約(7種類)
Leading(Left or Right) Alignment, Trailing(Right or Left) Alignment, Center X AlignmentTop Alignment, Bottom Alignment, Center Y Alignment, Baseline Alignment
• 相対位置に関する制約(2種類)Horizontal SpaceVertical Space
• サイズに関する制約(2種類)Width, Height
• サイズの連動に関する制約(2種類)Equal Widths, Equal Heights
制約の種類• アライメントに関する制約(7種類)
Leading(Left or Right) Alignment, Trailing(Right or Left) Alignment, Center X AlignmentTop Alignment, Bottom Alignment, Center Y Alignment, Baseline Alignment
• 相対位置に関する制約(2種類)Horizontal SpaceVertical Space
• サイズに関する制約(2種類)Width, Height
• サイズの連動に関する制約(2種類)Equal Widths, Equal Heights
実際に追加される制約は13種類
制約の種類• アライメントに関する制約(7種類)
Leading(Left or Right) Alignment, Trailing(Right or Left) Alignment, Center X AlignmentTop Alignment, Bottom Alignment, Center Y Alignment, Baseline Alignment
• 相対位置に関する制約(2種類)Horizontal SpaceVertical Space
• サイズに関する制約(2種類)Width, Height
• サイズの連動に関する制約(2種類)Equal Widths, Equal Heights
実際に追加される制約は13種類大きく分類すると4種類
制約の種類• Interface Builder 上から実行できる制約追加のコマンド
は 19 種類
• でも実際には、制約の種類と制約の適用対象のバリエーションの組み合わせで Interface Builder のコマンドの種類が多くなっているだけ
• 制約の適用対象のバリエーション• 親ビューとその子コンポーネント• 兄弟コンポーネント同士• 対象コンポーネントのみ
User Constraint• Interface Builder 上で設定される制約には
2種類あり、アイコンの色が異なっている
• 青いアイコンはユーザー編集可能な制約を表す( User Constraint )キャンバス上の制約インジケーターが太い
• 紫のアイコンは Interface Builder が自動的に挿入した制約キャンバス上の制約インジケーターが細い
User Constraint
• User Constraint はシーンやキャンバス、サイズインスペクタから削除することができる
• Interface Builder が追加した制約は、サイズインスペクタの Constraints で対象の制約を選び、 Promote to User Constraint を選択すると User Constraint にすることができる
IB で Auto Layout を利用するとよくわからない動きをする・・・
• Auto Layout は実行時にレイアウトを決定するのに十分な制約を設定する必要がある
• 必要となる制約が不足している場合、 Interface Builder が制約を自動で設定する• このため、制約を編集すると既存の制約が壊
されるように感じる
IB で Auto Layout を利用する際のポイント
• 自動設定された制約(紫アイコン)とユーザー設定の制約(青アイコン)を意識すると思い通りに設定できる
• 実体である NSLayoutConstraint を意識する
NSLayoutConstraint で制約を設定する
NSLayoutConstraint
• レイアウトの制約を表すクラス
• 基本的にイミュータブルなので、制約を変更する際は新しいインスタンスを作成して差し替える
NSLayoutConstraint の計算式
属性値 1 == 属性値 2 * 乗数 + 定数
NSLayoutConstraint• id firstItem
• 属性値の計算結果を反映するオブジェクト
• NSLayoutAttribute firstAttribute• 計算結果を反映する属性• firstItem で指定されたオブジェクトに対して、この属性に対応する値を属性値
として反映する
• id secondItem• 計算式に利用する属性値を取得するオブジェクト
• NSLayoutAttribute secondAttribute• 計算式に利用する属性• 属性値の取得元は secondItem で指定されたオブジェクト
NSLayoutConstraint• id firstItem
• 属性値の計算結果を反映するオブジェクト
• NSLayoutAttribute firstAttribute• 計算結果を反映する属性• firstItem で指定されたオブジェクトに対して、この属性に対応する値を属性値
として反映する
• id secondItem• 計算式に利用する属性値を取得するオブジェクト
• NSLayoutAttribute secondAttribute• 計算式に利用する属性• 属性値の取得元は secondItem で指定されたオブジェクト
firstItem は計算結果を反映する側secondItem は計算式に値を利用する側
NSLayoutConstraint• CGFloat constant
• 計算式の中で属性値の算出に利用する定数値• この値だけは、例外的に NSLayoutConstraint のインスタンス化後に変更できる
• CGFloat multiplier• 計算式の中で属性値の算出に利用する乗算値• 属性値同士の比率を定義するのに使用する• 今のところ乗算値を利用した制約の定義は Interface Builder でサポートされて
いない
• NSLayoutPriority priority• 制約の優先順位
• NSLayoutRelation relation• 計算式とその計算結果の関係性を指定する
NSLayoutAttribute
• 制約の対象となる属性を表す列挙型
• ボタン1の「下端」から 10px 下側に、ボタン2の「上端」がくるよう配置する制約の場合• ボタン1の属性は NSLayoutAttributeBottom• ボタン2の属性は NSLayoutAttributeTop
NSLayoutAttributetypedef NS_ENUM(NSInteger, NSLayoutAttribute) { NSLayoutAttributeLeft = 1, NSLayoutAttributeRight, NSLayoutAttributeTop, NSLayoutAttributeBottom, NSLayoutAttributeLeading, NSLayoutAttributeTrailing, NSLayoutAttributeWidth, NSLayoutAttributeHeight, NSLayoutAttributeCenterX, NSLayoutAttributeCenterY, NSLayoutAttributeBaseline, NSLayoutAttributeNotAnAttribute = 0};
NSLayoutRelation
• 計算式とその計算結果の関係性を表す列挙型
• 「等しい」「以上」「以下」の3つ
typedef NS_ENUM(NSInteger, NSLayoutRelation) { NSLayoutRelationLessThanOrEqual = -1, NSLayoutRelationEqual = 0, NSLayoutRelationGreaterThanOrEqual = 1,};
NSLayoutPriority• 競合する制約間の優先順位を表す値
• この値が高い制約から優先的に制約で定義された条件が満たされていく
• 1 から 1000までの CGFloat値
• いくつかの定数値が UILayoutPriority 列挙型として用意されているので、基本的にこの値を利用するのがよさそう
enum { UILayoutPriorityRequired = 1000, UILayoutPriorityDefaultHigh = 750, UILayoutPriorityDefaultLow = 250, UILayoutPriorityFittingSizeLevel = 50};typedef float UILayoutPriority;
NSLayoutConstraint の計算式
属性値 1 == 属性値 2 * 乗数 + 定数
NSLayoutConstraint の計算式
属性値 1 == 属性値 2 * 乗数 + 定数
firstItemfirstAttribute
secondItemsecondAttribute
multiplier
constant
relation
NSLayoutConstraint の計算式• ボタン1の右端から右に 10px の位置にボタン2の左端が位置
する場合
button2.left == button1.right * 1 + 10
• ビュー2の幅がビュー1の幅の3倍の場合
view2.width == view1.width * 3 + 0
NSLayoutConstraint の計算式• ボタン1の右端から右に 10px の位置にボタン2の左端が位置
する場合
button2.left == button1.right * 1 + 10
• ビュー2の幅がビュー1の幅の3倍の場合
view2.width == view1.width * 3 + 0
すべての制約は計算式で表現される
NSLayoutConstraint の作成
[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[view1]-|" options:0 metrics:nil views:views];
• Visual Format Language を利用する方法
[NSLayoutConstraint constraintWithItem:view1 attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:view2 attribute:NSLayoutAttributeHeight multiplier:2.0f constant:0.0f];
• Visual Format Language を利用しない方法
Visual Format Language
• 制約を NSString で表現する DSL のようなもの
@"V:|-[view1]-20-[view2]-|”
Visual Format Language
• 制約を NSString で表現する DSL のようなもの
@"V:|-[view1]-20-[view2]-|”
"V:"垂直方向のレイアウト
"|"親ビューの
エッジ
“[view2]"コンポーネントのインスタンス
"-20-"20px のスペース
"-"スペース
(デフォルト値)
Visual Format Language
• 制約を NSString で表現する DSL のようなもの
@"V:|-[view1]-20-[view2]-|”
以下の3つの制約を表現している・垂直方向において、 view1 の上端は親ビューの上端からデフォルト値( 20px )下にある・垂直方向において、 view1 の下端と view2 の上端は 20px 離れている・垂直方向において、 view2 の下端は親ビューの下端からデフォルト値( 20px )上にある
Visual Format Language
• 文字列なのでコンパイラによるチェックはない
• 実行時にパースできないとエラーが発生する
• 詳細は Apple の公式ドキュメントを参照
Visual Format Languagehttps://developer.apple.com/library/ios/#documentation/UserExperience/Conceptual/AutolayoutPG/Articles/formatLanguage.html
Demo
コードNSDictionary *views = NSDictionaryOfVariableBindings(view1, view2);
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[view1]-|" options:0 metrics:nil views:views]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[view1]-20-[view2]-|" options:NSLayoutFormatAlignAllCenterX metrics:nil views:views]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:[view1(==view2)]" options:0 metrics:nil views:views]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:view1 attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:view2 attribute:NSLayoutAttributeHeight multiplier:2.0f constant:0.0f]];
Auto Layout 補足
Intrinsic Content Size• 一部の UI コンポーネントは自身の推奨サイズを、 UIView で定義
された intrinsicConstentSize メソッドから取得できる
• UIButton, UILabel などが推奨サイズを持っている
• ラベルのみの UIButton であれば、内部のテキストの幅・高さにパディングを加えたものが推奨サイズとなる
• 内部のコンテンツの大きさが変化すると、推奨サイズも変化する
• Auto Layout においては、幅や高さを決定する制約が不足している場合に推奨サイズが使用される
推奨サイズを持たない場合
Center X Alignment
Vertical Space (148)
Vertical Space (149)
Horizontal Space (36)
推奨サイズを持つ場合
Center X Alignment
Vertical Space (148)
推奨サイズを持つ場合
Center X Alignment
Vertical Space (148)
ボタンの幅と高さは推奨サイズが採用されるので、制約を追加する必要なし
推奨サイズの優先順位• まわりのコンポーネントの制約によっては、推奨サイズを実現できないときがある
• 制約同士が競合した場合と同じように、推奨サイズも優先順位がつけられて実際のレイアウトに適用される• Content Hugging Priority• Content Compression Resistance Priority
Content Hugging Priority
• UI コンポーネントのサイズが制約によって推奨サイズより大きくなる場合の「大きくなりにくさ」を決定する
• 実際には NSLayoutPriority の値で制約間での優先順位を設定している
• デフォルト値は UILayoutPriorityDefaultLow
• UIView にメソッドが用意されている– contentHuggingPriorityForAxis:– setContentHuggingPriority:forAxis:
Content Compression Resistance Priority
• UI コンポーネントのサイズが制約によって推奨サイズより小さくなる場合の「小さくなりにくさ」を決定する
• Content Hugging Priority 同様、実際には優先順位の値が設定される
• デフォルト値は UILayoutPriorityDefaultHigh
• UIView にメソッドが用意されている– contentCompressionResistancePriorityForAxis:– setContentCompressionResistancePriority:forAxis:
動的なレイアウトへの対応• ビューのプロパティが変更された場合など
に、動的にレイアウトを変更したい
• 今までは layoutSubviews をオーバーライドしてレイアウト処理を書いていた
• 制約を利用する場合も、同じように UIViewに制約変更用のライフサイクルメソッドが用意されている
動的なレイアウトへの対応- updateConstraints
• オーバーライドして制約の更新処理を記述する• layoutSubviews と同じく、システムによって呼ばれるので自
分で呼び出さない• このメソッドをオーバーライドする場合は、 layoutSubviews
によるレイアウト処理はオーバーライドしないこと• 逆に layoutSubviews をオーバーライドする場合
は、 updateConstraint はオーバーライドしない
- setNeedsUpdateConstraints• updateConstraints の実行をトリガする• layoutSubviews に対する setNeedsLayout と同じ
Auto Layout のデバッグUIView の UIConstraintBasedLayoutDebugging カテゴリに定義されているデバッグ用のメソッドを利用する
• - (NSArray *)constraintsAffectingLayoutForAxis:(UILayoutConstraintAxis)axis縦軸・横軸のそれぞれについて、現在適用されている制約を返すUILayoutConstraintAxis で制約を取得したい軸を指定する
• - (BOOL)hasAmbiguousLayout制約が不足してレイアウトが決定できない箇所がある場合 YES を返す
• - (void)exerciseAmbiguityInLayouthasAmbiguousLayout が YES の場合、可能性のあるレイアウトをランダムで画面に適用するリリースビルド作成の際は必ずこれらのメソッドは外すこ
と!
Demo
Auto Layout のメリット• より柔軟なレイアウトを frame を操作せず
に実現できる
• 込み入ったレイアウトを宣言的にプログラミングすることができる
• Visual Format Language による定義が手軽
Auto Layout のデメリット• 学習コストが低いとは言えない
• シンプルなレイアウトを組むの場合はAutoResizingMask を使う方が手軽
• iOS5 では使えない
ご清聴ありがとうございました