FlowRow
和 FlowColumn
是与 Row
和 Column
类似的可组合项,但不同之处在于,当容器空间不足时,项目会流到下一行。这会创建多行或多列。还可以通过设置 maxItemsInEachRow
或 maxItemsInEachColumn
来控制每行中的项目数。您通常可以使用 FlowRow
和 FlowColumn
来构建响应式布局——如果项目对于一个维度太大,内容不会被截断,并且结合使用 maxItemsInEach*
和 Modifier.weight(weight)
可以帮助构建在需要时填充/扩展行或列宽度的布局。
典型的示例是芯片或过滤 UI
基本用法
要使用 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,当第一行没有更多空间时,项目会自动流到下一行。
Flow 布局的功能
Flow 布局具有以下功能和属性,您可以使用它们在您的应用中创建不同的布局。
主轴排列:水平或垂直排列
主轴是项目排列的轴(例如,在 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 个项目
未设置最大值 |
|
延迟加载 Flow 项目
ContextualFlowRow
和 ContextualFlowColumn
是 FlowRow
和 FlowColumn
的一个专门版本,允许您延迟加载 Flow 行或列的内容。它们还提供有关项目位置(索引、行号和可用大小)的信息,例如项目是否在第一行。这对于大型数据集以及您需要有关项目的上下文信息时很有用。
参数 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()
在 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) ) } } }
每个项目都应用了 |
|
未设置宽度更改(项目换行) |
推荐内容
- 注意:当 JavaScript 关闭时,将显示链接文本。
- Compose 布局基础
- Compose 中的 ConstraintLayout
- 编辑器操作 {:#editor-actions}