制約と修飾子の順序

Compose では、複数の修飾子を連結して、コンポーザブルの外観を変更できます。これらの修飾子チェーンは、幅と高さの境界を定義するコンポーザブルに渡される制約に影響する可能性があります。

このページでは、チェーン修飾子が制約にどのように影響し、ひいてはコンポーザブルの測定と配置にどのように影響するかについて説明します。

UI ツリーの修飾子

修飾子が互いにどのように影響し合うかを理解するには、コンポジション フェーズで生成される UI ツリーに修飾子がどのように表示されるかを可視化すると便利です。詳細については、コンポジションのセクションをご覧ください。

UI ツリーでは、修飾子をレイアウト ノードのラッパーノードとして可視化できます。

コンポーザブルと修飾子のコード、およびそれらの UI ツリーとしての視覚的表現。
図 1: UI ツリー内のレイアウト ノードをラップする修飾子

コンポーザブルに複数の修飾子を追加すると、修飾子のチェーンが作成されます。複数の修飾子を連鎖させると、各修飾子ノードがチェーンの残りとその中のレイアウト ノードをラップします。たとえば、clip 修飾子と size 修飾子を連結すると、clip 修飾子ノードが size 修飾子ノードをラップし、この修飾子ノードが Image レイアウト ノードをラップします。

レイアウト フェーズでは、ツリーをたどるアルゴリズムは同じままですが、各修飾子ノードもアクセスされます。これにより、修飾子は、ラップする修飾子またはレイアウト ノードのサイズ要件と配置を変更できます。

図 2 に示すように、Image コンポーザブルと Text コンポーザブルの実装自体は、単一のレイアウト ノードをラップする修飾子のチェーンで構成されています。RowColumn の実装は、子のレイアウト方法を記述するレイアウト ノードです。

以前のツリー構造ですが、各ノードは単純なレイアウトで、多くの修飾子がノードを囲んでいます。
図 2. 図 1 と同じツリー構造ですが、UI ツリー内のコンポーザブルは修飾子のチェーンとして可視化されます。

まとめ

  • 修飾子は、単一の修飾子またはレイアウト ノードをラップします。
  • レイアウト ノードは複数の子ノードを配置できます。

以降のセクションでは、このメンタルモデルを使用して修飾子チェーンについて推論する方法と、それがコンポーザブルのサイズに与える影響について説明します。

レイアウト フェーズの制約

レイアウト フェーズでは、次の 3 ステップのアルゴリズムに従って、各レイアウト ノードの幅、高さ、x、y 座標を特定します。

  1. 子を測定: ノードはその子(存在する場合)を測定します。
  2. 独自のサイズを決定する: これらの測定値に基づいて、ノードは独自のサイズを決定します。
  3. 子を配置する: 各子ノードは、ノード自体の位置を基準として配置されます。

Constraints は、アルゴリズムの最初の 2 つのステップで、ノードに適したサイズを見つけるのに役立ちます。制約は、ノードの幅と高さの最小値と最大値を定義します。ノードがサイズを決定するとき、測定されたサイズはこのサイズ範囲内に収まる必要があります。

制約のタイプ

制約は次のいずれかです。

  • 制限付き: ノードには最大および最小の幅と高さがあります。
コンテナ内のさまざまなサイズの制限付き制約。
図 3. 制限付き制約
  • 制限なし: ノードはサイズに制限されません。幅と高さの最大境界は無限大に設定されています。
幅と高さが無限大に設定された制限なしの制約。制約はコンテナを超えて拡張されます。
図 4.制限なしの制約
  • 完全一致: ノードは正確なサイズ要件に従うように求められます。最小値と最大値は同じ値に設定されています。
コンテナ内の正確なサイズ要件に準拠する正確な制約。
図 5.正確な制約。
  • 組み合わせ: ノードは上記の制約タイプの組み合わせに従います。たとえば、最大の高さを制限せずに幅を制限したり、正確な幅を設定して高さを制限したりできます。
制限付き制約と制限なし制約の組み合わせ、および正確な幅と高さの組み合わせを表示する 2 つのコンテナ。
図 6.制限付き制約と制限なし制約の組み合わせ、正確な幅と高さ

次のセクションでは、これらの制約が親から子に渡される仕組みについて説明します。

親から子に制約を渡す方法

レイアウト フェーズの制約で説明されているアルゴリズムの最初のステップで、制約は UI ツリーの親から子に受け渡されます。

親ノードが子を測定する際は、それぞれの子にこれらの制約を設定して、許容される大きさを知らせます。その後、自身のサイズを決定すると、自身の親から渡された制約も遵守されます。

アルゴリズムの仕組みの概要は次のとおりです。

  1. 実際に占有するサイズを決定するため、UI ツリーのルートノードはその子を測定し、同じ制約を最初の子に転送します。
  2. 子が測定に影響しない修飾子の場合は、制約を次の修飾子に転送します。測定に影響する修飾子に到達しない限り、制約はそのまま修飾子チェーンに渡されます。制約はそれに応じてサイズ変更されます。
  3. 子を持たないノード(「リーフノード」)に到達すると、渡された制約に基づいてサイズを決定し、解決されたサイズを親に返します。
  4. 親はこの子の測定値に基づいて制約を調整し、調整された制約で次の子を呼び出します。
  5. 親のすべての子が測定されると、親ノードは自身のサイズを決定し、それを親ノードに伝えます。
  6. このようにして、ツリー全体が深さ優先で走査されます。最終的には、すべてのノードでサイズが決定され、測定ステップが完了します。

詳細な例については、制約と修飾子の順序の動画をご覧ください。

制約に影響する修飾子

前のセクションでは、一部の修飾子が制約サイズに影響する可能性があることを学びました。以降のセクションでは、制約に影響を与える特定の修飾子について説明します。

size 修飾子

size 修飾子は、コンテンツの推奨サイズを宣言します。

たとえば、次の UI ツリーは、200dp による 300dp のコンテナでレンダリングする必要があります。制約は制限付きで、幅は 100dp300dp の範囲、高さは 100dp200dp の範囲で指定してください。

レイアウト ノードをラップするサイズ修飾子を含む UI ツリーの一部と、コンテナ内のサイズ修飾子によって設定された制限付き制約の表現。
図 7. UI ツリーの制限付き制約とコンテナ内のその表現

size 修飾子は、渡された値と一致するように受信制約を調整します。この例では、値は 150dp です。

図 7 と同じですが、渡された値に一致するように受信制約を適応させるサイズ修飾子点が異なります。
図 8. 制約を 150dp に調整する size 修飾子。

幅と高さが最小の制約境界よりも小さい場合、または最大の制約境界よりも大きい場合、修飾子は、渡された制約を遵守しながら、渡された制約とできる限り一致します。

2 つの UI ツリーとそれに対応するコンテナ内の表現。1 つ目の方法では、サイズ修飾子が incmoing の制約を受け入れます。2 つ目の方法では、大きすぎる制約に可能な限り近く適応するため、コンテナいっぱいに制約が発生します。
図 9. 渡された制約に可能な限り厳密に準拠する size 修飾子

複数の size 修飾子のチェーン化は機能しません。最初の size 修飾子は、最小制約と最大制約の両方を固定値に設定します。2 番目のサイズ修飾子が小さいサイズまたは大きいサイズをリクエストする場合でも、渡された正確な境界に従う必要があるため、これらの値はオーバーライドされません。

UI ツリー内の 2 つのサイズ修飾子のチェーンと、コンテナ内でのその表現。2 番目の値ではなく、渡された最初の値の結果です。
図 10. 2 つの size 修飾子のチェーンで、2 番目の値(50dp)が最初の値(100dp)をオーバーライドしない。

requiredSize 修飾子

ノードで受信制約をオーバーライドする必要がある場合は、size ではなく requiredSize 修飾子を使用します。requiredSize 修飾子は受信制約を置き換え、指定したサイズを正確な境界として渡します。

サイズがツリーの上方に渡されると、子ノードが使用可能なスペースの中央に配置されます。

UI ツリー内でチェーンされているサイズと requiredSize の修飾子と、コンテナ内の対応する表現。requiredSize 修飾子の制約はサイズ修飾子の制約をオーバーライドします。
図 11. size 修飾子からの受信制約をオーバーライドする requiredSize 修飾子。

width 修飾子と height 修飾子

size 修飾子は、制約の幅と高さの両方を調整します。width 修飾子を使用すると、幅を固定しても高さは固定できます。同様に、height 修飾子を使用すると、高さを固定できますが、幅は未定です。

2 つの UI ツリー。1 つは幅修飾子とそのコンテナ表現を、もう 1 つは高さ修飾子とその表現を含んでいます。
図 12. 固定の幅と高さを設定する width 修飾子と height 修飾子。

sizeIn 修飾子

sizeIn 修飾子を使用すると、幅と高さに正確な最小値と最大値の制約を設定できます。制約をきめ細かく制御する必要がある場合は、sizeIn 修飾子を使用します。

幅と高さの最小値と最大値が設定された sizeIn 修飾子を含む UI ツリーと、コンテナ内でのその表現。
図 13. minWidthmaxWidthminHeightmaxHeight が設定された sizeIn 修飾子。

このセクションでは、チェーン修飾子を使用した複数のコード スニペットの出力を示し、説明します。

Image(
    painterResource(R.drawable.hero),
    contentDescription = null,
    Modifier
        .fillMaxSize()
        .size(50.dp)
)

このスニペットは、次の出力を生成します。

  • fillMaxSize 修飾子は制約を変更して、最小の幅と最小の高さの両方を最大値(幅は 300dp、高さは 200dp)に設定します。
  • size 修飾子は 50dp のサイズを使用しようとしますが、指定された最小制約を遵守する必要があります。したがって、size 修飾子は 200 による 300 の正確な制約境界も出力し、size 修飾子で指定された値は実質的に無視されます。
  • Image はこれらの境界に従い、300 のサイズを 200 で報告します。これはツリーの一番上まで渡されます。

Image(
    painterResource(R.drawable.hero),
    contentDescription = null,
    Modifier
        .fillMaxSize()
        .wrapContentSize()
        .size(50.dp)
)

このスニペットは、次の出力を生成します。

  • fillMaxSize 修飾子は制約を適応させて、最小の幅と高さの両方を最大値(幅は 300dp、高さを 200dp)に設定します。
  • wrapContentSize 修飾子は、最小制約をリセットします。そのため、fillMaxSize では固定制約が設定されますが、wrapContentSize では制限付き制約にリセットされます。次のノードは、スペース全体を占有することも、スペース全体よりも小さくすることもできます。
  • size 修飾子は、制約を 50 の最小境界と最大境界に設定します。
  • Image50 × 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 × 100 のサイズを報告します。
    • padding 修飾子はすべてのサイズで 10dp を追加するため、レポートされる幅と高さが 20dp 増加します。
    • 描画フェーズでは、clip 修飾子が 120 のキャンバスに 120dp で作用します。そのサイズの円マスクを作成します。
    • padding 修飾子は、すべてのサイズで 10dp でコンテンツを挿入するため、キャンバス サイズが 100dp だけ 100 に引き下げられます。
    • Image がそのキャンバスに描画されます。画像は 120dp の元の円に基づいてクリップされるため、出力は丸くありません。