如何强制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行,超出则横向滚动:
- 添加依赖:
implementation "com.google.accompanist:accompanist-flowlayout:0.35.1-alpha"
- 实现代码:
@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
相关产品推荐
相关产品推荐

