Compose 中的流式布局

FlowRowFlowColumnRowColumn 类似,但不同之处在于,当容器空间不足时,项会流入下一行。这会创建多行或多列。您还可以通过设置 maxItemsInEachRowmaxItemsInEachColumn 来控制行中的项数量。您通常可以使用 FlowRowFlowColumn 构建自适应布局,这样一来,如果某个维度上的项过大,内容就不会被截断;将 maxItemsInEach*Modifier.weight(weight) 组合使用有助于构建在需要时填充/扩展行或列宽度的布局。

典型的示例如下所示,适用于条状标签或过滤界面:

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")
    }
}

此代码段会生成上图所示的界面,当第一行没有空间时,项会自动流向下一行。

流式布局的功能

流布局具有以下功能和属性,可用于在应用中创建不同的布局。

主轴排列方式:水平排列或垂直排列

主轴是内容布局的轴(例如,在 FlowRow 中,内容是水平排列的)。FlowRow 中的 horizontalArrangement 参数用于控制可用空间在项之间分配的方式。

下表显示了为 FlowRow 对项设置 horizontalArrangement 的示例:

对于 FlowColumnverticalArrangement 提供了类似的选项,默认值为 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 和 max 项与 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 账号。