Windows Phone のレイアウトとパネル
2012/12/11
対象: Windows Phone 8 | Windows Phone OS 7.1
ここでは、Windows Phone のレイアウト システムについて説明します。見た目のよい、高パフォーマンスのユーザー インターフェイスを作成するには、アプリの要素がページに配置される方法と、レイアウトの計算が行われる方法およびタイミングを理解することが重要です。
このトピックは、次のセクションで構成されています。
- レイアウト システム
- 要素の境界ボックス
- 子のサイズ測定と配置
- パネル要素とカスタム レイアウトの動作
- ウィンドウ サイズの変更または向きの変化
- 関連トピック
レイアウト システム
レイアウトという用語は、Windows Phone アプリに配置するオブジェクトのサイズと位置を決定するプロセスを表します。ビジュアル オブジェクトを配置するには、Panel またはその他のコンテナー オブジェクトに配置する必要があります。親の Panel には、Panel 要素の Children コレクションのメンバーをどのように画面に描画するかを決定するレイアウト動作が定義されています。これは負荷の高いプロセスで、Children コレクションが大きくなるにつれ、実行される計算の数も多くなります。コレクションを所有する Panel 要素で定義されるレイアウト動作のために、複雑になる場合もあります。Canvas などの比較的単純なレイアウトが使用され、Grid などのより複雑な Panel が不要な場合は、優れたパフォーマンスを実現できます。
子 UIElement の位置が変更されるたびに、レイアウト システムによって新しいパスがトリガーされる可能性があります。レイアウト システムを呼び出す可能性があるイベントを理解し、不要な呼び出しによってアプリのパフォーマンスが低下しないようにすることが重要です。
簡単に言うと、レイアウトは、要素のサイズ測定、配置、および画面上での描画を繰り返す反復型のシステムです。レイアウト システムは、Children コレクションのメンバーごとに 2 つのパスを実行します。最初に測定パスを実行し、次に配置パスを実行します。測定パスでは、子要素の必要なサイズが決定されます。配置パスでは、それぞれの子要素のサイズと位置が最終的に決定されます。
注意
要素のレイアウトに注目するときは、要素の境界ボックスのレイアウトに注目すると、精度がより向上します。詳細については、このトピックに後ほど登場する「要素の境界ボックス」を参照してください。
既定の Panel レイアウト動作をオーバーライドすることを目的として、各種の Panel はそれぞれ固有のレイアウト動作を提供するために独自の MeasureOverride メソッドと ArrangeOverride メソッドを提供します。これは、レイアウト システムが呼び出されるたびに発生する一連のイベントです。
それぞれの子 UIElement が測定されます。
Width、Height、Margin など、FrameworkElement で定義されるサイズ設定プロパティが評価されます。
スタックに関連する Orientation など、Panel 固有のロジックが適用されます。
すべての子が測定された後、コンテンツが配置されます。
Children コレクションが画面に描画されます。
Children がコレクションに追加された場合、Width や Height など Children のレイアウト プロパティが変更された場合、または UpdateLayout メソッドが呼び出された場合は、プロセスが再度呼び出されます。
このプロセス、およびプロセスが呼び出される方法については、以降のセクションで詳しく定義します。
要素の境界ボックス
Windows Phone アプリですべての要素を囲む境界ボックスを理解することが重要です。この抽象化は、レイアウト システムの動作を理解する上で役に立ちます。レイアウト システムが FrameworkElement の配置を行うときは、要素を含む四角形 (レイアウト スロット) が実際に配置されます。
要素のレイアウト スロットと可視領域の幾何学的な境界を返すことができるように、LayoutInformation クラスが公開されています。レイアウト スロットのサイズは、システムにより、使用可能な画面スペース、制約のサイズ、余白やパディングなどのレイアウト固有のプロパティ、および親 Panel 要素の個々の動作を計算して決定されます。このデータに基づき、システムは特定の Panel に属するすべての子の位置を計算できます。親要素で定義されたサイズ設定特性 (Border など) は、その子に影響する点に注意することが重要です。
次の図は、親パネル、その子パネル、および、その子を含むレイアウト スロットの寸法を示しています。
子に割り当てられた領域は、子要素よりもかなり大きいことがわかります。領域の決定は親コンテナーに依存し、それぞれの子のレイアウト スロットのサイズが決定されます。親は、子が求めるよりも広い領域または狭い領域を割り当てることができます。レイアウト スロットの寸法は、GetLayoutSlot を呼び出すことで取得できます。次に、親は、子に設定されている配置プロパティに基づいて、レイアウト スロット内部に子を配置します。
次の図は、子要素が回転され、割り当てられたレイアウト スロットの範囲を超えて広がっているようすを示しています。
この場合、レイアウト システムは子要素をクリップし、レイアウト スロット内に収まる要素部分だけを表示します。赤色で縁取りされたこの可視領域は "レイアウト クリップ" と呼ばれるもので、GetLayoutClip を呼び出すことでその寸法を取得できます。GetLayoutClip は Geometry オブジェクトを返すため、可視領域は必ずしも四角形ではありません。
要素を囲む境界ボックスは、親コンテナーに要素が追加されると変化することがあります。追加される要素の種類やサイズに応じて、縮小または拡大することがあります。
子のサイズ測定と配置
要素を画面に表示する必要がある場合や、要素のサイズが変更された場合は、レイアウト システムが起動されます。レイアウトの最初のパスは測定パスです。ここで、子要素の必要なサイズが測定されます。2 番目のパスは配置パスです。ここでは、それぞれの子要素の境界ボックスの最終的なサイズと位置が決定されます。
測定
測定パスでは、レイアウト システムは Panel に対してその availableSize を伝えます。これは、親が子をレイアウトするために Panel で利用できる領域です。Panel は、それぞれの子のネイティブのサイズ プロパティ (Clip や Visibility など) を評価します。
次に、それぞれの子に定義されている FrameworkElement プロパティが処理されます。これらのプロパティは、多くの場合、Height、Width、Margin、Style など、基になる UIElement のサイズ特性を表しています。これらの各プロパティにより、要素の表示に必要な領域が変更されることがあります。Panel は、それぞれの子の Measure メソッドを呼び出します。その際、子が利用できるサイズを渡します。利用可能なサイズを、子が要求したサイズにすることはできますが、親は、レイアウトが必要な要素の数やその availableSize に基づいて、子のサイズを制限することもできます。
注意
Height および Width と ActualHeight および ActualWidth の各プロパティには違いがあります。たとえば、ActualHeight プロパティは、他の高さの入力やレイアウト システムを基に計算された値です。この値は、実際の描画パスに基づいて、レイアウト システム自体によって設定されるため、入力変更の基準となる Height などのプロパティの設定値よりも少し遅れることがあります。既定値は 0 であるため、Height と Width を設定する必要があります。
ActualHeight は計算値であるため、レイアウト システムによるさまざまな操作の結果として、複数または追加の変更がレポートされる可能性があることに注意してください。子要素、親要素による制約などに必要な測定空間をレイアウト システムが計算している場合があります。
測定パスの最終的な目標は、レイアウト システムでそれぞれの子の DesiredSize が決定されることです。これは、Measure が呼び出された後に内部的に行われます。この値は、配置プロセス中に格納されて使用されます。
配置
配置パスでは、レイアウト システムは Panel に対し、パネルおよびその子が利用できる finalSize を伝えます。配置パスの実行中、親である Panel 要素は子の DesiredSize と要素の表示サイズに影響する可能性のある余白を評価し、子の境界ボックスを個別に決定します。境界ボックスによって、子のレイアウト スロットの寸法が決まります。次に、親 Panel はそれぞれの子の Arrange メソッドを呼び出します。その際、対象となる子のパネル内での起点、高さ、および幅が設定された Rect を渡します。
注意
すべてのレイアウトは、親要素が基準となります。起点を 0,0 に設定した場合、子要素は親パネルの左上隅に配置されます。
レイアウト システムは、余白や配置などのオフセット プロパティの最終的な評価を行い、レイアウト スロット内に子を配置します。子は、割り当てられた領域全体を占める必要はなく、実際に、全体を占めないことも珍しくありません。次に、制御が親 Panel に戻されて、レイアウト プロセスが完了します。
パネル要素とカスタム レイアウトの動作
多くの複雑なレイアウトを有効にする Panel 要素の派生スイートを使用できます。要素のスタックなどの一般的なシナリオは StackPanel 要素を使用して簡単に実現できますが、Grid を使用すると、より複雑なレイアウトを実現できます。
使用可能なレイアウト要素を次の表に示します。
パネル名 |
説明 |
---|---|
Canvas 領域に対する相対座標を使用して、子要素を明示的に配置できる領域を定義します。 |
|
列と行で構成されている柔軟なグリッド領域を定義します。 |
|
子要素を水平方向または垂直方向の直線状に整列します。 |
これらのレイアウト コンテナーのそれぞれでは、子の配置方法に影響を与える可能性があるさまざまなプロパティが考慮されます。一般的なプロパティの一部を次の表に示します。
プロパティ名 |
レイアウトへの影響 |
---|---|
オブジェクトとレイアウト スロットの間に空白を作成します。 |
|
レイアウト スロット内にオブジェクトを配置します。 |
|
オブジェクトどうしが重なる場合に 1 つのオブジェクト上に別のオブジェクトを配置します。 |
パネル レイアウト ロジックを適用することに加え、変換とアニメーションを使用してオブジェクトの位置を変更することもできます。
定義された Panel 要素のいずれを使用しても実現できないアプリ レイアウトが必要とされる場合は、Panel からの継承と、MeasureOverride メソッドおよび ArrangeOverride メソッドを使用して測定や配置の既定の動作をオーバーライドすることにより、カスタムのレイアウト動作を実現できます。
ウィンドウ サイズの変更または向きの変化
Canvas を使用したオブジェクトの絶対配置は一部のシナリオでは有効ですが、サイズまたは向きが変化するアプリでは不適切です。絶対配置では向きが変化したときにページ上でオブジェクトが再配置されず、オブジェクトは指定されたピクセル位置に配置されたままになります。
StackPanel および Grid を使用すると、コンテンツを再配置できます。Grid オブジェクトは、Visual Studio Windows Phone テンプレートで使用されるルート要素です。Grid は他の Panel オブジェクトより使用方法が複雑ですが、多様なオブジェクト レイアウトを作成するために必要な柔軟性を備えており、これを使用することでコンテンツを再配置できるようになります。
最適なウィンドウ サイズの変更動作を利用できるようにするには、(Panel オブジェクトを使用して子オブジェクトを配置する以外に) 一般的には XAML ファイルのルート要素またはレイアウトのルート要素からすべての幅/高さ宣言を削除することをお勧めします。