Compose 中的流程版面配置

FlowRow 和 FlowColumn 是與 Row 和 Column 類似的可組合函式,但不同之處在於,當容器空間用盡時,項目會流動到下一行。這會建立多個資料列或資料欄。您也可以設定 maxItemsInEachRow 或 maxItemsInEachColumn,控制一行中的項目數量。您通常可以使用 FlowRow 和 FlowColumn 建構回應式版面配置,如果項目太大而無法容納在一個維度中,內容就不會遭到截斷,而搭配使用 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 中,項目會水平排列)。FlowRow 中的 horizontalArrangement 參數可控制項目之間可用空間的分配方式。

下表列出為 FlowRow 商品設定 horizontalArrangement 的範例:

已在「FlowRow」上設定水平排列

結果

Arrangement.Start (Default)

項目靠左排列

Arrangement.SpaceBetween

項目排列方式,中間有空格

Arrangement.Center

項目置中排列

Arrangement.End

排列在最後的項目

Arrangement.SpaceAround

項目周圍有空格

Arrangement.spacedBy(8.dp)

項目間隔特定 dp

如果是 FlowColumn,verticalArrangement 也有類似的選項,預設值為 Arrangement.Top。

交錯軸排列

交錯軸是與主軸方向相反的軸。舉例來說,在 FlowRow 中,這是垂直軸。如要變更容器內整體內容在交叉軸中的排列方式,請針對 FlowRow 使用 verticalArrangement,針對 FlowColumn 使用 horizontalArrangement。

下表列出在 FlowRow 項目上設定不同 verticalArrangement 的範例:

FlowRow 的垂直排列方式設定

結果

Arrangement.Top (Default)

容器頂端排列

Arrangement.Bottom

容器底部排列

Arrangement.Center

容器置中排列

FlowColumn 則可使用 horizontalArrangement 提供的類似選項。預設的交錯軸排列方式為 Arrangement.Start。

個別項目對齊

您可能想在資料列中,以不同的對齊方式放置個別項目。這與 verticalArrangement 和 horizontalArrangement 不同,因為它會對齊「目前行內」的項目。您可以使用 Modifier.align() 套用這項設定。

舉例來說,如果 FlowRow 中的項目高度不同,資料列會採用最大項目高度,並將 Modifier.align(alignmentOption) 套用至項目:

在 FlowRow 上設定垂直對齊

結果

Alignment.Top (Default)

所有項目靠上對齊

Alignment.Bottom

項目靠下對齊

Alignment.CenterVertically

項目置中對齊

FlowColumn 也有類似選項。預設對齊方式為 Alignment.Start。

資料列或資料欄中的項目數量上限

參數 maxItemsInEachRow 或 maxItemsInEachColumn 定義了主軸中單行允許的最大項目數,超過這個數量就會換行。預設值為 Int.MAX_INT,只要大小允許,就能盡可能放入多個項目。

舉例來說,設定 maxItemsInEachRow 會強制初始版面配置只包含 3 個項目:

未設定上限

maxItemsInEachRow = 3

流程列未設定上限 流程列設定的項目數量上限

項目權重

權重會根據項目係數和所在行的可用空間,增加項目大小。重要的是,FlowRow 和 Row 在使用權重計算項目寬度的方式上有所不同。Rows 的權重是根據Row中的所有項目計算。使用 FlowRow 時,權重是根據項目所在行中的項目計算,而非 FlowRow 容器中的所有項目。

舉例來說,如果一列有 4 個項目,每個項目的權重分別為 1f, 2f, 1f 和 3f,則總權重為 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)
    }
}

重要的是,如果您新增另一個項目並重複 10 次 (而非 9 次),最後一個項目會佔用整個最後一欄,因為整列的總權重為 1f:

格狀檢視畫面中的最後一個項目以完整大小顯示
圖 3. 使用 FlowRow 建立格線,最後一個項目會佔用完整寬度

您可以將字重與其他 Modifiers 結合,例如 Modifier.width(exactDpAmount), Modifier.aspectRatio(aspectRatio) 或 Modifier.fillMaxWidth(fraction)。這些修飾符會搭配運作,讓 FlowRow (或 FlowColumn) 中的項目能回應式調整大小。

您也可以建立不同項目大小的交替格線,其中兩個項目各占一半寬度,一個項目占滿下一個資料欄的寬度:

交替網格與流動列
圖 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 項目會占用剩餘寬度的百分比,而非整個容器的寬度。

舉例來說,使用 FlowRow 和 Row 時,下列程式碼會產生不同的結果:

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()

將 Modifier.fillMaxColumnWidth() 或 Modifier.fillMaxRowHeight() 套用至 FlowColumn 或 FlowRow 中的項目,可確保同一欄或同一列中的項目寬度或高度與該欄/列中最大的項目相同。

舉例來說,本範例使用 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

未設定寬度變更 (換行項目)

未設定填滿最大欄寬