Compose の Flow レイアウト

FlowRowFlowColumnRowColumn と似たコンポーザブルですが、コンテナのスペースがなくなるとアイテムが次の行に流れる点が異なります。これにより、複数の行または列が作成されます。1 行あたりのアイテム数は、maxItemsInEachRow または maxItemsInEachColumn を設定して制御することもできます。FlowRowFlowColumn は、レスポンシブ レイアウトの作成によく使用されます。アイテムが 1 つのディメンションに対して大きすぎる場合でもコンテンツが切り取られることはありません。また、maxItemsInEach*Modifier.weight(weight) を組み合わせることで、必要に応じて行または列の幅を埋める/拡張するレイアウトを作成できます。

一般的な例としては、チップやフィルタリング UI があります。

FlowRow 内の 5 つのチップ。スペースがなくなると次の行にオーバーフローします。
図 1.FlowRow の例

基本的な使用方法

FlowRow または FlowColumn を使用するには、これらのコンポーザブルを作成し、標準フローに従うアイテムをその中に配置します。

@Composable
private fun FlowRowSimpleUsageExample() {
    FlowRow(modifier = Modifier.padding(8.dp)) {
        ChipItem("Price: High to Low")
        ChipItem("Avg rating: 4+")
        ChipItem("Free breakfast")
        ChipItem("Free cancellation")
        ChipItem("£50 pn")
    }
}

このスニペットでは、上記の UI が生成されます。最初の行にスペースがなくなると、アイテムは自動的に次の行に流れます。

フロー レイアウトの機能

フロー レイアウトには、アプリでさまざまなレイアウトを作成するために使用できる次の機能とプロパティがあります。

メイン軸の配置: 水平方向または垂直方向の配置

メイン軸は、アイテムが配置される軸です(たとえば、FlowRow では、アイテムは水平方向に配置されます)。FlowRowhorizontalArrangement パラメータは、アイテム間の空きスペースの配分方法を制御します。

次の表に、FlowRow のアイテムに horizontalArrangement を設定する例を示します。

FlowRow に設定された水平方向の配置

結果

Arrangement.StartDefault

開始で配置されたアイテム

Arrangement.SpaceBetween

アイテムの配置(アイテム間にスペースあり)

Arrangement.Center

アイテムが中央に配置されている

Arrangement.End

最後に配置されたアイテム

Arrangement.SpaceAround

アイテムが配置され、周囲にスペースがある

Arrangement.spacedBy(8.dp)

アイテムが特定の dp で間隔を空けている

FlowColumn の場合、同様のオプションを verticalArrangement で使用できます。デフォルトは Arrangement.Top です。

交差軸の配置

交差軸は、メイン軸と反対方向の軸です。たとえば、FlowRow では、これは垂直軸です。コンテナ内のコンテンツ全体の交差軸での配置方法を変更するには、FlowRow には verticalArrangementFlowColumn には horizontalArrangement を使用します。

FlowRow の場合、次の表に、アイテムに異なる verticalArrangement を設定する例を示します。

FlowRow に設定された垂直方向の配置

結果

Arrangement.TopDefault

コンテナの最上部のアレンジ

Arrangement.Bottom

コンテナの下部の配置

Arrangement.Center

コンテナ センターの配置

FlowColumn の場合、同様のオプションを horizontalArrangement で使用できます。デフォルトの交差軸の配置は Arrangement.Start です。

個々のアイテムの配置

行内の個々のアイテムを異なる配置で配置することが必要な場合があります。これは、verticalArrangementhorizontalArrangement とは異なり、現在の行内のアイテムを配置します。 これは Modifier.align() で適用できます。

たとえば、FlowRow のアイテムの高さが異なる場合、行は最も大きいアイテムの高さになり、アイテムに Modifier.align(alignmentOption) が適用されます。

FlowRow に設定された垂直方向の配置

結果

Alignment.TopDefault

上揃えにされたアイテム

Alignment.Bottom

下揃えにされたアイテム

Alignment.CenterVertically

中央揃えにされたアイテム

FlowColumn の場合、同様のオプションを使用できます。デフォルトの配置は Alignment.Start です。

行または列の最大アイテム数

パラメータ maxItemsInEachRow または maxItemsInEachColumn は、次の行に折り返す前に 1 行に配置できるメイン軸の最大アイテム数を定義します。デフォルトは Int.MAX_INT です。サイズが許す限り、できるだけ多くのアイテムを 1 行に配置できます。

たとえば、maxItemsInEachRow を設定すると、最初のレイアウトには 3 つのアイテムのみが配置されます。

最大値が設定されていない場合

maxItemsInEachRow = 3

フロー行に最大値が設定されていない フローの行に設定された最大アイテム数

アイテムの重み

重みは、アイテムの係数と、配置された行の空きスペースに基づいてアイテムを拡大します。重要な点として、FlowRowRow では、アイテムの幅を計算するために重みが使用される方法が異なります。Rows の場合、重み は すべてのアイテム に基づきます。RowFlowRow の場合、重みは アイテムが配置されている行のアイテム に基づきます。 FlowRow コンテナ内のすべてのアイテムではありません。

たとえば、4 つのアイテムがすべて 1 行に配置され、それぞれの重みが 1f, 2f, 1f3f の場合、合計の重みは 7f になります。行または列の残りのスペースは 7f で除算されます。次に、各アイテムの幅は weight * (remainingSpace / totalWeight) を使用して計算されます。

Modifier.weight と最大アイテム数を FlowRow または FlowColumn と組み合わせて使用すると、グリッドのようなレイアウトを作成できます。この方法は、デバイスのサイズに合わせて調整されるレスポンシブ レイアウトを作成する場合に便利です。

重みを使用して実現できることには、いくつかの異なる例があります。たとえば、次の図に示すように、アイテムのサイズが均等なグリッドがあります。

フロー行で作成されたグリッド
図 2.FlowRow を使用してグリッドを作成する

アイテムのサイズが均等なグリッドを作成するには、次の操作を行います。

val rows = 3
val columns = 3
FlowRow(
    modifier = Modifier.padding(4.dp),
    horizontalArrangement = Arrangement.spacedBy(4.dp),
    maxItemsInEachRow = rows
) {
    val itemModifier = Modifier
        .padding(4.dp)
        .height(80.dp)
        .weight(1f)
        .clip(RoundedCornerShape(8.dp))
        .background(MaterialColors.Blue200)
    repeat(rows * columns) {
        Spacer(modifier = itemModifier)
    }
}

重要な点として、9 回ではなく 10 回繰り返して別のアイテムを追加すると、行全体の合計の重みが 1f になるため、最後のアイテムが最後の列全体を占有します。

グリッドの最後のアイテムがフルサイズ
図 3.FlowRow を使用して、最後のアイテムが幅全体を占有するグリッドを作成する

重みは、Modifier.width(exactDpAmount), Modifier.aspectRatio(aspectRatio)Modifier.fillMaxWidth(fraction) などの他の Modifiers と組み合わせることができます。これらの修飾子はすべて連携して動作し、FlowRow(または FlowColumn)内のアイテムのサイズをレスポンシブに調整できます。

また、2 つのアイテムがそれぞれ幅の半分を占有し、1 つのアイテムが次の列の幅全体を占有する、異なるアイテムサイズの交互のグリッドを作成することもできます。

フロー行を含む交互のグリッド
図 4.FlowRow 行のサイズが交互に変わる

これは、次のコードで実現できます。

FlowRow(
    modifier = Modifier.padding(4.dp),
    horizontalArrangement = Arrangement.spacedBy(4.dp),
    maxItemsInEachRow = 2
) {
    val itemModifier = Modifier
        .padding(4.dp)
        .height(80.dp)
        .clip(RoundedCornerShape(8.dp))
        .background(Color.Blue)
    repeat(6) { item ->
        // if the item is the third item, don't use weight modifier, but rather fillMaxWidth
        if ((item + 1) % 3 == 0) {
            Spacer(modifier = itemModifier.fillMaxWidth())
        } else {
            Spacer(modifier = itemModifier.weight(0.5f))
        }
    }
}

分数サイズ設定

Modifier.fillMaxWidth(fraction) を使用すると、アイテムが占有するコンテナのサイズを指定できます。これは、 Modifier.fillMaxWidth(fraction)Row または Column に適用した場合の動作とは異なります。 Row/Column アイテムは、コンテナの幅全体ではなく、残りの幅の割合を占有します。

たとえば、次のコードでは、FlowRowRow を使用した場合で異なる結果が生成されます。

FlowRow(
    modifier = Modifier.padding(4.dp),
    horizontalArrangement = Arrangement.spacedBy(4.dp),
    maxItemsInEachRow = 3
) {
    val itemModifier = Modifier
        .clip(RoundedCornerShape(8.dp))
    Box(
        modifier = itemModifier
            .height(200.dp)
            .width(60.dp)
            .background(Color.Red)
    )
    Box(
        modifier = itemModifier
            .height(200.dp)
            .fillMaxWidth(0.7f)
            .background(Color.Blue)
    )
    Box(
        modifier = itemModifier
            .height(200.dp)
            .weight(1f)
            .background(Color.Magenta)
    )
}

FlowRow: コンテナの幅全体の 0.7 の分数を持つ中央のアイテム。

フロー行の分数幅

Row: 残りの Row の幅の 0.7% を占有する中央のアイテム。

行の幅の割合

fillMaxColumnWidth()fillMaxRowHeight()

FlowColumn または FlowRow 内のアイテムに Modifier.fillMaxColumnWidth() または Modifier.fillMaxRowHeight() を適用すると、同じ列または行のアイテムが、列または行内の最大のアイテムと同じ幅または高さになります。

たとえば、この例では FlowColumn を使用して Android のデザートのリストを表示します。Modifier.fillMaxColumnWidth() がアイテムに適用されている場合と、適用されていない場合で、各アイテムの幅が異なることがわかります。

FlowColumn(
    Modifier
        .padding(20.dp)
        .fillMaxHeight()
        .fillMaxWidth(),
    horizontalArrangement = Arrangement.spacedBy(8.dp),
    verticalArrangement = Arrangement.spacedBy(8.dp),
    maxItemsInEachColumn = 5,
) {
    repeat(listDesserts.size) {
        Box(
            Modifier
                .fillMaxColumnWidth()
                .border(1.dp, Color.DarkGray, RoundedCornerShape(8.dp))
                .padding(8.dp)
        ) {

            Text(
                text = listDesserts[it],
                fontSize = 18.sp,
                modifier = Modifier.padding(3.dp)
            )
        }
    }
}

Modifier.fillMaxColumnWidth() が各アイテムに適用されました

fillMaxColumnWidth

幅の変更が設定されていない場合(アイテムの折り返し)

最大列幅が設定されていない