制約の変更
制約の変更は、制約の基礎となる数式を変更するものです (図 17-1 を参照のこと)。制約方程式の詳細については、制約の構造 を参照してください。
図 17-1 制約方程式
以下のアクションはすべて、1 つ以上の制約を変更します。
- 制約の活性化または非活性化
- 制約の定数値を変更
- 制約の優先順位を変更
- ビュー階層からのビューの削除
コントロールのプロパティの設定やビュー階層の変更など、その他の変更によっても制約が変更されえます。変更が発生すると、システムは遅延レイアウトパスをスケジュールします (遅延レイアウトパス を参照の事)。
通常、これらの変更はいつでも行うことができます。理想的には、ほとんどの制約は Interface Builder で設定するか、コントローラの初期設定中に (たとえば、viewDidLoad で) ビューコントローラーによってプログラムで作成する必要があります。実行時に動的に制約を変更する必要がある場合は、通常、アプリケーションの状態が変化したときに制約を変更するのが最善です。たとえば、ボタンのタップに応じて制約を変更したい場合は、ボタンのアクションメソッドで直接変更します。
パフォーマンス上の理由により、一連の変更をバッチ処理する必要がある場合があります。詳細については、変更のバッチ処理 を参照してください。
遅延レイアウトパス
影響を受けるビューのフレームをすぐに更新する代わりに、自動レイアウトは近い将来のレイアウトパスをスケジュール化します。この遅延パスにより、レイアウトの制約が更新され、それからビュー階層内のすべてのビューのフレームが計算されます。
setNeedsLayout メソッドまたは setNeedsUpdateConstraints メソッドを呼び出すことにより、独自の遅延レイアウトパスをスケジュール化できます。
遅延レイアウトパスには、実際にはビュー階層を通る 2 つのパスが含まれます。
- 更新パスは、必要に応じて制約を更新します
- レイアウトパスは、必要に応じてビューのフレームを再配置します
更新パス
システムはビュー階層を走査し、すべてのビューコントローラ上で updateViewConstraints メソッドを呼び出し、すべてのビュー上で updateConstraints メソッドを呼び出します。これらのメソッドをオーバーライドして、制約への変更を最適化できます (変更のバッチ処理 を参照の事)。
レイアウトパス
システムは再びビュー階層を走査し、すべてのビューコントローラ上で viewWillLayoutSubviews を呼び出し、すべてのビューで layoutSubviews (OS Xではlayout) を呼び出します。デフォルトでは、 layoutSubviews メソッドは、自動レイアウトエンジンによって計算された長方形で各サブビューのフレームを更新します。これらのメソッドをオーバーライドして、レイアウトを変更できます (カスタムレイアウト を参照の事)。
変更のバッチ処理
ほとんどの場合、影響のある変更が発生した直後に制約を更新する方がより綺麗で簡単です。これらの変更を後のメソッドに遅延すると、コードがより複雑になり、理解するのが難しくなります。
ただし、パフォーマンス上の理由から、変更をバッチ処理したい場合があります。これは、所定の場所での制約の変更が遅すぎる場合、またはビューが多数の冗長な変更を行っている場合にのみ行います。
変更を直接行うのではなく、変更をバッチ処理するには、制約を保持しているビュー上で setNeedsUpdateConstraints メソッドを呼び出します。それから、ビューの updateConstraints メソッドをオーバーライドして、影響を受ける制約を変更します。
あなたが updateConstraints を実装するのは、可能な限り効率的でなければなりません。すべての制約を非活性化せずに、必要なものを再度活性化してください。代わりに、あなたのアプリには制約を追跡し、各更新パス中に制約を検証する何らかの方法がなければなりません。変更が必要な項目のみを変更します。各更新パスの間、アプリの現在の状態に適切な制約があることを確認しなければなりません。
updateConstraints メソッドの実装の最後のステップとして、常にスーパークラスの実装を呼び出して下さい。
updateConstraints メソッド内で setNeedsUpdateConstraints を呼び出さないでください。setNeedsUpdateConstraints を呼び出すと、別の更新パスがスケジュール化され、フィードバックループが作成されます。
カスタムレイアウト
viewWillLayoutSubviews メソッドまたは layoutSubviews メソッドをオーバーライドして、レイアウトエンジンから返される結果を変更します。
可能であれば、制約を使用してすべてのレイアウトを定義します。結果のレイアウトはより堅牢で、デバッグが容易です。制約だけでは表現できないレイアウトを作成する必要がある場合は、 viewWillLayoutSubviews メソッドまたは layoutSubviews メソッドのみをオーバーライドする必要があります。
これらのメソッドをオーバーライドすると、レイアウトが不整合な状態になります。すでにいくつかのビューがレイアウトされています。他のビューはされていません。ビュー階層を変更する方法については非常に注意する必要があります。そうしないと、フィードバックループを作成する可能性があります。以下のルールは、フィードバックループを回避するのに役立ちます。
- メソッドのどこかでスーパークラスの実装を呼び出さなければなりません。
- サブツリー内のビューのレイアウトを安全に無効化できます。ただし、スーパークラスの実装を呼び出す前にこれをしなければなりません。
- サブツリー外のビューのレイアウトを無効にしないでください。これにより、フィードバックループが作成される可能性があります。
- setNeedsUpdateConstraints を呼び出さないでください。更新パスを完了しています。このメソッドを呼び出すと、フィードバックループが作成されます。
- setNeedsLayout を呼び出さないでください。このメソッドを呼び出すと、フィードバックループが作成されます。
- 制約の変更には注意してください。サブツリー外のビューのレイアウトを誤って無効にしたくない場合は。
前:自動サイズ化テーブルビューセルの操作 次:視覚書式言語