Compose 中的流程版面配置

FlowRowFlowColumn 是類似於 RowColumn 的可組合元件,但差別在於容器空間用盡時,項目會流入下一行。即可建立多個資料列或資料欄。您也可以設定 maxItemsInEachRowmaxItemsInEachColumn,控制一行中的項目數量。您通常可以使用 FlowRowFlowColumn 建構回應式版面配置,如果項目太大而無法放入單一維度,系統就不會截斷內容,而且將 maxItemsInEach*Modifier.weight(weight) 搭配使用,有助於在需要時建構可填滿/展開資料列或欄寬度的版面配置。

常見的例子是用於方塊或篩選 UI:

FlowRow 中的 5 個方塊,顯示在空間用盡時,溢流至下一行的情況。
圖 1. FlowRow 的範例

基本用法

如要使用 FlowRowFlowColumn,請建立這些可組合項,並在其中放置應遵循標準流程的項目:

@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 的範例:

FlowColumn 的類似選項可透過 verticalArrangement 使用,預設為 Arrangement.Top

交錯軸排列

交叉軸是與主軸相反的軸線。例如,在 FlowRow 中,這是垂直軸。如要變更容器內部整體內容在交叉軸上的排列方式,請將 FlowRow 設為 verticalArrangement,將 FlowColumn 設為 horizontalArrangement

針對 FlowRow,下表列出在項目上設定不同 verticalArrangement 的示例:

FlowRow 上設定垂直排列方式

結果

Arrangement.Top (Default)

容器頂端排列方式

Arrangement.Bottom

容器底部排列

Arrangement.Center

容器中心排列

FlowColumnhorizontalArrangement 提供類似的選項。預設的橫向軸排列方式為 Arrangement.Start

個別項目對齊

您可能會想在列中以不同對齊方式放置個別項目。這與 verticalArrangementhorizontalArrangement 不同,因為它會將項目對齊在目前的文字行內。您可以使用 Modifier.align() 套用此設定。

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

FlowRow 上設定垂直對齊

結果

Alignment.Top (Default)

項目靠上對齊

Alignment.Bottom

項目靠下對齊

Alignment.CenterVertically

項目置中對齊

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

列或欄中的項目數量上限

參數 maxItemsInEachRowmaxItemsInEachColumn 會定義主軸中允許在單一行中顯示的項目上限,並在轉換至下一行的過程中保留這些項目。預設值為 Int.MAX_INT,可讓盡可能多的項目,只要尺寸可放入該行即可。

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

未設定上限

maxItemsInEachRow = 3

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

延遲載入流程項目

ContextualFlowRowContextualFlowColumnFlowRowFlowColumn 的專屬版本,可讓您延後載入流程列或欄的內容。這些屬性也會提供項目位置 (索引、資料列編號和可用大小) 的相關資訊,例如項目是否位於第一列。這項功能適用於大型資料集,以及需要項目相關資訊的情況。

maxLines 參數會限制顯示的列數,而 overflow 參數則會指定在項目溢出時應顯示的內容,讓您指定自訂 expandIndicatorcollapseIndicator

舉例來說,如要顯示「+ (剩餘項目數量)」或「顯示較少項目」按鈕:

val totalCount = 40
var maxLines by remember {
    mutableStateOf(2)
}

val moreOrCollapseIndicator = @Composable { scope: ContextualFlowRowOverflowScope ->
    val remainingItems = totalCount - scope.shownItemCount
    ChipItem(if (remainingItems == 0) "Less" else "+$remainingItems", onClick = {
        if (remainingItems == 0) {
            maxLines = 2
        } else {
            maxLines += 5
        }
    })
}
ContextualFlowRow(
    modifier = Modifier
        .safeDrawingPadding()
        .fillMaxWidth(1f)
        .padding(16.dp)
        .wrapContentHeight(align = Alignment.Top)
        .verticalScroll(rememberScrollState()),
    verticalArrangement = Arrangement.spacedBy(4.dp),
    horizontalArrangement = Arrangement.spacedBy(8.dp),
    maxLines = maxLines,
    overflow = ContextualFlowRowOverflow.expandOrCollapseIndicator(
        minRowsToShowCollapse = 4,
        expandIndicator = moreOrCollapseIndicator,
        collapseIndicator = moreOrCollapseIndicator
    ),
    itemCount = totalCount
) { index ->
    ChipItem("Item $index")
}

內容流程列的示例。
圖 2. ContextualFlowRow 的範例

商品重量

權重會根據項目的因數和放置項目的線條可用空間,增加項目的權重。請注意,FlowRowRow 在使用權重來計算項目寬度的方式上有所不同。對於 Rows,權重會根據 Row 中的所有項目計算。在 FlowRow 中,權重會根據項目放置在哪個項目所在的列決定,而非 FlowRow 容器中的所有項目。

舉例來說,如果有 4 個項目都落在同一行,且各自有不同的 1f, 2f, 1f3f 權重,則總權重為 7f。列或欄中的剩餘空間會除以 7f。接著,系統會使用 weight * (remainingSpace / totalWeight) 計算每個項目的寬度。

您可以將 Modifier.weight 和最大項目與 FlowRowFlowColumn 結合,建立類似格狀的版面配置。這種做法可用於建立可調整為裝置大小的回應式版面配置。

以下列舉幾個使用權重可達成的效果。其中一個範例是項目大小相同的格狀檢視畫面,如下所示:

使用流動列建立的格狀檢視畫面
圖 3. 使用 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

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

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

您也可以建立不同項目大小的格線交替畫面,其中兩個項目各佔一半寬度,一個項目則佔用下一個欄的整個寬度:

交替式格狀與流動列
圖 5. 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) 套用至 RowColumn 時的運作方式不同,因為 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()

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

舉例來說,這個範例會使用 FlowColumn 顯示 Android 甜點清單。您可以看到,當 Modifier.fillMaxColumnWidth() 套用至項目時,每個項目的寬度與未套用 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

未設定寬度變更 (項目包裝)

未設定填滿欄寬上限

目前沒有任何建議。

建議 Google 帳戶。