17、流式布局

39 阅读2分钟

Compose 中的流式布局

FlowRowFlowColumn 是类似于 RowColumn 的可组合项,但不同之处在于,当容器空间不足时,项目会流入下一行(或列)。这会创建多行或多列布局,非常适合构建自适应界面。

基本用法

@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 中是水平轴)。使用 horizontalArrangement 参数控制项目间的空间分配:

FlowRow(
    horizontalArrangement = Arrangement.SpaceBetween // 或其他排列方式
) { /* items */ }

FlowRow 的主轴排列选项包括:

  • Arrangement.Start (默认值)
  • Arrangement.SpaceBetween
  • Arrangement.Center
  • Arrangement.End
  • Arrangement.SpaceAround
  • Arrangement.spacedBy(8.dp)

对于 FlowColumn,使用 verticalArrangement 获得类似选项。

交叉轴排列

交叉轴是与主轴方向相反的轴。在 FlowRow 中是垂直轴,使用 verticalArrangement 控制:

FlowRow(
    verticalArrangement = Arrangement.Center // 垂直居中排列各行
) { /* items */ }

FlowRow 的交叉轴排列选项包括:

  • Arrangement.Top (默认值)
  • Arrangement.Bottom
  • Arrangement.Center

对于 FlowColumn,使用 horizontalArrangement 获得类似选项。

单个项目对齐

可以使用 Modifier.align() 为行内各个项目设置不同的对齐方式:

FlowRow {
    Box(Modifier.align(Alignment.Bottom).size(50.dp, 80.dp))
    Box(Modifier.align(Alignment.CenterVertically).size(50.dp, 60.dp))
    Box(Modifier.align(Alignment.Top).size(50.dp, 40.dp))
}

FlowRow 中的对齐选项包括:

  • Alignment.Top (默认值)
  • Alignment.Bottom
  • Alignment.CenterVertically

行/列中的项目数量上限

maxItemsInEachRowmaxItemsInEachColumn 参数限制一行/列中的最大项目数:

FlowRow(
    maxItemsInEachRow = 3 // 每行最多3个项目
) { /* items */ }

项目权重

Modifier.weight 根据项目所在行/列中的可用空间分配宽度。与 Row 不同,FlowRow 中的权重只考虑当前行中的项目:

FlowRow(
    modifier = Modifier.padding(4.dp),
    horizontalArrangement = Arrangement.spacedBy(4.dp),
    maxItemsInEachRow = 3
) {
    val itemModifier = Modifier
        .padding(4.dp)
        .height(80.dp)
        .weight(1f)
        
    repeat(9) {
        Spacer(modifier = itemModifier.background(Color.Blue))
    }
}

创建网格布局

结合 maxItemsInEachRowweight 可以创建自适应网格:

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(Color.Blue200)
        
    repeat(rows * columns) {
        Spacer(modifier = itemModifier)
    }
}

交替网格大小

创建不同大小的项目网格:

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 ((item + 1) % 3 == 0) {
            Spacer(modifier = itemModifier.fillMaxWidth())
        } else {
            Spacer(modifier = itemModifier.weight(0.5f))
        }
    }
}

分数大小调整

Modifier.fillMaxWidth(fraction) 指定项目应占用的容器大小比例,与在 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(
    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))
        }
    }
}

使用流式布局可以轻松创建自适应界面,特别适合处理动态内容或不同屏幕尺寸的场景。