Compose では、複数の修飾子を連結してコンポーザブルの外観を変更できます。これらの修飾子チェーンは、コンポーザブルに渡される制約に影響を与える可能性があります。制約は、幅と高さの境界を定義します。
このページでは、連結された修飾子が制約にどのように影響し、その結果、コンポーザブルの測定と配置にどのように影響するかについて説明します。
UI ツリー内の修飾子
修飾子が互いにどのように影響するかを理解するには、コンポジション フェーズで生成される UI ツリーに修飾子がどのように表示されるかを可視化すると便利です。詳細については、コンポジションのセクションをご覧ください。
UI ツリーでは、修飾子をレイアウト ノードのラッパーノードとして可視化できます。
コンポーズ可能な関数に複数の修飾子を追加すると、修飾子のチェーンが作成されます。複数の修飾子を連結すると、各修飾子ノードは、チェーンの残りの部分とレイアウト ノードを内部にラップします。たとえば、clip 修飾子と
size 修飾子を連結すると、clip 修飾子ノードが size 修飾子ノードをラップし、
修飾子ノードが Image レイアウト ノードをラップします。
レイアウト フェーズでは、ツリーを走査するアルゴリズムは同じですが、各修飾子ノードもアクセスされます。これにより、修飾子は、ラップする修飾子またはレイアウト ノードのサイズ要件と配置を変更できます。
図 2 に示すように、Image コンポーザブルと Text コンポーザブル自体の実装は、1 つのレイアウト ノードをラップする修飾子のチェーンで構成されています。
Row と Column の実装は、子のレイアウト方法を記述するレイアウト ノードです。
まとめ
- 修飾子は、単一の修飾子またはレイアウト ノードをラップします。
- レイアウト ノードは複数の子ノードをレイアウトできます。
以降のセクションでは、このメンタルモデルを使用して修飾子の連鎖と、それがコンポーザブルのサイズに及ぼす影響について説明します。
レイアウト フェーズでの制約
レイアウト フェーズでは、3 ステップのアルゴリズムに従って、各レイアウト ノードの幅、高さ、x 座標、y 座標を特定します。
- 子を測定する: ノードは、子があれば測定します。
- 自身のサイズを決定する: ノードは、測定値に基づいて自身のサイズを決定します。
- 子を配置する: 各子ノードは、ノード自身の位置を基準として配置されます。
Constraints は、アルゴリズムの最初の 2 つのステップでノードの適切なサイズを見つけるのに役立ちます。制約は、ノードの幅と高さの最小値と最大値を定義します。ノードがサイズを決定するとき、測定されたサイズはこのサイズ範囲内に入る必要があります。
制約の種類
制約は次のいずれかになります。
- 境界あり: ノードには幅と高さの最大値と最小値があります。
- 無制限: ノードのサイズに制限はありません。幅と高さの上限は無限に設定されます。
- Exact: ノードは、正確なサイズ要件に従うように求められます。最小境界と最大境界は同じ値に設定されます。
- 組み合わせ: ノードは、前述の制約タイプの組み合わせに従います。たとえば、制約によって幅を制限し、最大高さを無制限にすることも、幅を正確に設定し、高さを制限することもできます。
次のセクションでは、これらの制約が親から子にどのように渡されるかについて説明します。
制約が親から子に渡される仕組み
レイアウト フェーズの制約で説明したアルゴリズムの最初のステップでは、制約は UI ツリーの親から子に渡されます。
親ノードは、子を測定する際に、これらの制約を各子に提供して、許容されるサイズを知らせます。その後、自身のサイズを決定する際、自身の親から渡された制約も遵守します。
大まかに言うと、このアルゴリズムは次のように機能します。
- 実際に占有するサイズを決定するため、UI ツリーのルートノードは子を測定し、同じ制約を最初の子に転送します。
- 子が測定に影響しない修飾子である場合、制約を次の修飾子に転送します。制約は、測定に影響する修飾子に到達するまで、修飾子チェーンをそのまま渡されます。制約はそれに応じてサイズが変更されます。
- 子を持たないノード(「リーフノード」と呼ばれる)に到達すると、渡された制約に基づいてサイズを決定し、この解決されたサイズを親に返します。
- 親は、この子の測定値に基づいて制約を調整し、調整された制約を使用して次の子を呼び出します。
- 親のすべての子が測定されると、親ノードは自身のサイズを決定し、それを自身の親に伝えます。
- このようにして、ツリー全体が深さ優先で走査されます。最終的に、すべてのノードのサイズが決定され、測定ステップが完了します。
詳細な例については、制約と修飾子の順序の動画をご覧ください。
制約に影響する修飾子
前のセクションで説明したように、一部の修飾子は制約サイズに影響する可能性があります。以降のセクションでは、制約に影響する特定の修飾子について説明します。
size 修飾子
size 修飾子は、コンテンツの推奨サイズを宣言します。
たとえば、次の UI ツリーは、200dp によって 300dp のコンテナにレンダリングされる必要があります。制約は制限されており、幅は 100dp~300dp、高さは 100dp~200dp の範囲で指定できます。
size 修飾子は、渡された値に一致するように受信制約を調整します。この例では、値は 150dp です。
size 修飾子は、制約を 150dp に調整します。幅と高さが最小の制約境界より小さい場合、または最大の制約境界より大きい場合、修飾子は、渡された制約にできるだけ近づけながら、渡された制約に準拠します。
size 修飾子。複数の size 修飾子を連結しても機能しません。最初の size 修飾子は、最小制約と最大制約の両方を固定値に設定します。2 つ目のサイズ修飾子がより小さいサイズまたはより大きいサイズをリクエストしても、渡された正確な境界を遵守する必要があるため、それらの値はオーバーライドされません。
size 修飾子のチェーン。2 番目に渡された値(50dp)は、最初の値(100dp)をオーバーライドしません。requiredSize 修飾子
ノードで受信制約をオーバーライドする必要がある場合は、size の代わりに requiredSize 修飾子を使用します。requiredSize 修飾子は、受信制約を置き換え、指定したサイズを正確な境界として渡します。
サイズがツリーに返されると、子ノードは使用可能なスペースの中央に配置されます。
requiredSize 修飾子が、size 修飾子から渡される制約をオーバーライドします。width 修飾子と height 修飾子
size 修飾子は、制約の幅と高さの両方を調整します。width 修飾子を使用すると、幅を固定して高さを未決定のままにできます。同様に、height 修飾子を使用すると、高さを固定して幅を未決定のままにできます。
width 修飾子と height 修飾子は、それぞれ固定の幅と高さを設定します。sizeIn 修飾子
sizeIn 修飾子を使用すると、幅と高さの最小制約と最大制約を正確に設定できます。制約を細かく制御する必要がある場合は、sizeIn 修飾子を使用します。
sizeIn 修飾子。minWidth、maxWidth、minHeight、maxHeight が設定されています。例
このセクションでは、修飾子が連結された複数のコード スニペットの出力について説明します。
Image( painterResource(R.drawable.hero), contentDescription = null, Modifier .fillMaxSize() .size(50.dp) )
このスニペットは、次の出力を生成します。
Image は、修飾子チェーンの結果として最大サイズを埋めます。fillMaxSize修飾子は、幅と高さの両方の最小値を最大値(幅300dp、高さ200dp)に設定するように制約を変更します。size修飾子は50dpのサイズを使用しようとしますが、受信する最小制約を遵守する必要があります。そのため、size修飾子は300×200の正確な制約境界も出力し、size修飾子で指定された値を実質的に無視します。Imageはこれらの境界に従い、300x200のサイズを報告します。このサイズはツリー全体に渡されます。
Image( painterResource(R.drawable.hero), contentDescription = null, Modifier .fillMaxSize() .wrapContentSize() .size(50.dp) )
このスニペットは、次の出力を生成します。
Image は中央に配置され、50dp にサイズ設定されます。fillMaxSize修飾子は、制約を適応させて、幅と高さの両方の最小値を最大値(幅は300dp、高さは200dp)に設定します。wrapContentSize修飾子は最小制約をリセットします。したがって、fillMaxSizeによって固定制約が適用されましたが、wrapContentSizeによって制限付き制約に戻されます。次のノードは、スペース全体を再び占有することも、スペース全体よりも小さくすることもできます。size修飾子は、制約を50の最小境界と最大境界に設定します。Imageは50×50のサイズに解決され、size修飾子はそれを転送します。wrapContentSize修飾子には特別なプロパティがあります。子を受け取り、渡された使用可能な最小境界の中心に配置します。したがって、親に通知するサイズは、渡された最小境界と同じになります。
3 つの修飾子を組み合わせるだけで、コンポーザブルのサイズを定義し、親の中央に配置できます。
Image( painterResource(R.drawable.hero), contentDescription = null, Modifier .clip(CircleShape) .padding(10.dp) .size(100.dp) )
このスニペットは、次の出力を生成します。
clip修飾子は制約を変更しません。padding修飾子は、最大制約を下げます。size修飾子は、すべての制約を100dpに設定します。Imageはこれらの制約に従い、100dp×100dpのサイズを報告します。padding修飾子は、Imageによって報告されたサイズに、すべての辺で10dpを追加します。そのため、パディングを含むレイアウトは、幅と高さが120dpであると報告します。- 描画フェーズでは、
clip修飾子は120dpx120dpのキャンバスに作用します。そのサイズの円形マスクが作成されます。 padding修飾子は、コンテンツをすべての辺で10dpだけインセットします。これにより、Imageのキャンバス サイズが100dpx100dpに縮小されます。Imageは、その小さなキャンバスに描画されます。画像は120dpの元の円に基づいてクリップされるため、出力は円形以外の結果になります。