You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何强制Jetpack Compose LazyHorizontalGrid按行填充内容?

固定2行横向网格布局的6条目排列问题

问题描述

我实现了一个固定2行的HorizontalGridLayout,用于填充数量可变的条目:

  • 条目数量较多时显示正常;
  • 条目少于6个时已强制设为单行,效果良好;
  • 但条目数为6个时,希望第一行先填满,第6个条目单独显示在第二行(当前效果为每行3个,不符合预期)。

需求核心:既要类似FlowLayout的行优先排列,又要在条目较多时支持横向滚动,且最多显示2行。

当前实现代码

@Composable
fun HorizontalGridLayout(
    rowNumber: Int,
    columnList: List<@Composable (ColumnScope.() -> Unit)>,
    modifier: Modifier = Modifier,
) {
    LazyHorizontalGrid(
        modifier = modifier,
        rows = GridCells.Fixed(rowNumber),
        verticalArrangement = Arrangement.spacedBy(spacerSize),
        horizontalArrangement = Arrangement.spacedBy(spacerSize)
    ) {
        repeat(rowNumber) {
            item {
                Spacer(Modifier.width(horizontalSpacing))
            }
        }
        items(
            count = columnList.size,
            key = {
                columnList[it].hashCode()
            }, itemContent = { column ->
                Column(
                    content = columnList[column]
                )
                if (column < columnList.size - 1) {
                    Spacer(Modifier.width(spacerSize))
                }
            }
        )
        repeat(rowNumber) {
            item {
                Spacer(Modifier.width(horizontalSpacing))
            }
        }
    }
}

问题原因

LazyHorizontalGrid默认采用列优先的排列逻辑:先填满第一列的所有行,再填充第二列,因此6个条目(2行)会被分成3列,每行显示3个,不符合行优先的需求。

解决方案

方案1:自定义分支处理(不依赖第三方库)

根据条目数量分情况实现,针对6个条目手动拆分排列,其他情况保持原有逻辑:

@Composable
fun HorizontalGridLayout(
    rowNumber: Int,
    columnList: List<@Composable (ColumnScope.() -> Unit)>,
    modifier: Modifier = Modifier,
) {
    val itemCount = columnList.size
    val scrollState = rememberScrollState()

    when {
        // 少于6个条目:单行横向滚动
        itemCount < 6 -> {
            LazyRow(
                modifier = modifier.horizontalScroll(scrollState),
                horizontalArrangement = Arrangement.spacedBy(spacerSize),
                contentPadding = PaddingValues(horizontal = horizontalSpacing)
            ) {
                items(columnList) { item ->
                    Column(content = item)
                }
            }
        }
        // 刚好6个条目:第一行5个,第二行1个,横向滚动
        itemCount == 6 -> {
            LazyRow(
                modifier = modifier.horizontalScroll(scrollState),
                contentPadding = PaddingValues(horizontal = horizontalSpacing)
            ) {
                item {
                    Column(verticalArrangement = Arrangement.spacedBy(spacerSize)) {
                        Row(horizontalArrangement = Arrangement.spacedBy(spacerSize)) {
                            repeat(5) { index ->
                                Column(content = columnList[index])
                            }
                        }
                        Row(horizontalArrangement = Arrangement.spacedBy(spacerSize)) {
                            Column(content = columnList[5])
                        }
                    }
                }
            }
        }
        // 多于6个条目:保留原有2行横向网格逻辑
        else -> {
            LazyHorizontalGrid(
                modifier = modifier,
                rows = GridCells.Fixed(rowNumber),
                verticalArrangement = Arrangement.spacedBy(spacerSize),
                horizontalArrangement = Arrangement.spacedBy(spacerSize),
                contentPadding = PaddingValues(horizontal = horizontalSpacing)
            ) {
                items(columnList) { item ->
                    Column(content = item)
                }
            }
        }
    }
}

方案2:使用Accompanist FlowLayout(更通用)

借助Accompanist库的FlowRow组件,天然支持行优先排列,同时限制最多2行,超出则横向滚动:

  1. 添加依赖:
implementation "com.google.accompanist:accompanist-flowlayout:0.35.1-alpha"
  1. 实现代码:
@Composable
fun HorizontalGridLayout(
    rowNumber: Int,
    columnList: List<@Composable (ColumnScope.() -> Unit)>,
    modifier: Modifier = Modifier,
) {
    val itemCount = columnList.size
    val scrollState = rememberScrollState()

    if (itemCount < 6) {
        // 少于6个条目:单行横向滚动
        LazyRow(
            modifier = modifier.horizontalScroll(scrollState),
            horizontalArrangement = Arrangement.spacedBy(spacerSize),
            contentPadding = PaddingValues(horizontal = horizontalSpacing)
        ) {
            items(columnList) { item ->
                Column(content = item)
            }
        }
    } else {
        // >=6个条目:FlowRow行优先排列,最多2行,横向滚动
        FlowRow(
            modifier = modifier.horizontalScroll(scrollState),
            mainAxisSpacing = spacerSize,
            crossAxisSpacing = spacerSize,
            maxRows = 2,
            contentPadding = PaddingValues(horizontal = horizontalSpacing)
        ) {
            columnList.forEach { item ->
                Column(content = item)
            }
        }
    }
}

说明

  • 方案1无需依赖第三方库,逻辑直观,但仅针对6个条目做了特殊处理,适配不同屏幕宽度时不够灵活;
  • 方案2使用FlowRow,适配所有屏幕宽度,自动按行优先填满第一行后换行,最多2行,完全符合需求,推荐使用。

内容的提问来源于stack exchange,提问作者Jose Gonzalez

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 09:08:13