FlowRow
和 FlowColumn
是与 Row
和 Column
类似的可组合项,但不同之处在于,当容器空间不足时,项会流向下一行。这会创建多个行或列。您也可以通过设置 maxItemsInEachRow
或 maxItemsInEachColumn
来控制一行中的项目数量。您经常可以使用 FlowRow
和 FlowColumn
来构建自适应布局 - 如果项因一个尺寸而过大,则内容不会被截断;将 maxItemsInEach*
与 Modifier.weight(weight)
结合使用有助于构建在需要时填充/扩大行或列宽度的布局。
典型示例适用于条状标签或过滤界面:
基本用法
如需使用 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") } }
此代码段会生成如上所示的界面,当第一行没有更多空间时,项会自动移动到下一行。
流布局的功能
流式布局具有以下功能和属性,可用于在应用中创建不同的布局。
主轴排列方式:水平或垂直排列
主轴是布局项目的轴(例如,在 FlowRow
中,项目是水平排列的)。FlowRow
中的 horizontalArrangement
参数可控制在项之间分配可用空间的方式。
下表显示了针对 FlowRow
的项设置 horizontalArrangement
的示例:
已在“ |
结果 |
|
|
对于 FlowColumn
,verticalArrangement
提供了类似选项,默认值为 Arrangement.Top
。
横轴排列方式
交叉轴是与主轴相反的轴。例如,在 FlowRow
中,表示纵轴。如需更改容器内整体内容在横轴上的排列方式,请为 FlowRow
使用 verticalArrangement
,为 FlowColumn
使用 horizontalArrangement
。
对于 FlowRow
,下表显示了针对项设置不同 verticalArrangement
的示例:
|
结果 |
|
|
对于 FlowColumn
,horizontalArrangement
中也提供了类似选项。默认的交叉轴排列方式为 Arrangement.Start
。
单个项的对齐方式
您可能希望以不同的对齐方式放置行中的各个项。这与 verticalArrangement
和 horizontalArrangement
不同,因为它会对齐当前行中的项。您可以使用 Modifier.align()
来应用此设置。
例如,当 FlowRow
中的项的高度不同时,该行会采用最大项的高度,并将 Modifier.align(alignmentOption)
应用于各项:
已在 |
结果 |
|
|
对于 FlowColumn
,有类似选项可用。默认对齐方式为 Alignment.Start
。
行或列中的项数上限
参数 maxItemsInEachRow
或 maxItemsInEachColumn
定义了主轴上允许一行内的最大项数,然后再换行到下一行。默认值为 Int.MAX_INT
,表示允许尽可能多的项,只要其大小能容纳在行内即可。
例如,设置 maxItemsInEachRow
会强制初始布局仅包含 3 项内容:
未设置上限 |
|
延迟加载数据流项
ContextualFlowRow
和 ContextualFlowColumn
是 FlowRow
和 FlowColumn
的专用版本,可让您延迟加载数据流行或列的内容。这些视图还会提供有关项位置(索引、行号和可用大小)的信息,例如,项是否位于第一行。这对于大型数据集以及您需要有关某个项的上下文信息非常有用。
maxLines
参数用于限制显示的行数,overflow
参数用于指定在项目达到溢出值时应显示的内容,从而允许您指定自定义 expandIndicator
或 collapseIndicator
。
例如,要显示“+(剩余商品数量)”或“收起”按钮,请执行以下操作:
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") }
商品重量
权重会根据项的因数和其所在行的可用空间来增大项。重要的是,在计算某个项的宽度时,FlowRow
和 Row
之间存在区别。对于 Rows
,权重基于 Row
中的所有项。使用 FlowRow
时,权重的计算依据是某个项所在的行中的内容而不是 FlowRow
容器中的所有项。
例如,如果您有 4 个项全都放在同一行中,每个项的权重分别为 1f, 2f, 1f
和 3f
,则总权重为 7f
。行或列中的剩余空间会除以 7f
。然后,系统会使用 weight * (remainingSpace / totalWeight)
计算每个项宽度。
您可以将 Modifier.weight
和最大项数与 FlowRow
或 FlowColumn
结合使用,以创建类似于网格的布局。此方法对于创建可根据设备尺寸进行调整的响应式布局非常有用。
关于使用权重可以实现的目标,有几个不同的示例。例如,网格中各个项大小相等,如下所示:
如需创建项大小相同的网格,您可以执行以下操作:
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
:
您可以将权重与其他 Modifiers
(例如 Modifier.width(exactDpAmount), Modifier.aspectRatio(aspectRatio)
或 Modifier.fillMaxWidth(fraction)
)结合使用。这些修饰符全都协同工作,以实现自适应调整 FlowRow
(或 FlowColumn
)内的项的大小。
您还可以创建一个不同项大小的交替网格,其中两个项各自占据一半宽度,一个项占据下一列的整个宽度:
您可以使用以下代码实现此目的:
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)) }
|
|
|
“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) ) } } }
|
|
未设置宽度更改(封装项) |
为您推荐
- 注意:当 JavaScript 处于关闭状态时,系统会显示链接文字
- Compose 布局基础知识
- Compose 中的 ConstraintLayout
- 编辑器操作 {:#editor-actions}