Android Compose如何让LazyVerticalGrid行内项高度一致?
解决LazyVerticalGrid行内项等高问题
你的场景是网格项由图片+文本的Column组成,文本换行导致行内项高度不一致,且不想给所有项加不必要内边距来强制等高,以下是几种可行方案:
方案一:基于LazyListState动态计算行内最大高度
通过LazyListState获取每行的可见项,计算该行的最大高度,再给行内所有项统一设置这个高度。
@Composable fun EqualHeightLazyGrid(items: List<Item>) { val listState = rememberLazyGridState() val rowMaxHeights = remember { mutableStateMapOf<Int, Int>() } LaunchedEffect(listState.layoutInfo) { // 遍历可见行,计算每行最大高度 listState.layoutInfo.visibleItemsInfo.groupBy { it.row }.forEach { (rowIndex, items) -> val maxHeight = items.maxOfOrNull { it.size.height } ?: 0 rowMaxHeights[rowIndex] = maxHeight } } LazyVerticalGrid( columns = GridCells.Fixed(2), state = listState ) { itemsIndexed(items) { index, item -> val rowIndex = listState.layoutInfo.visibleItemsInfo.firstOrNull { it.index == index }?.row ?: 0 val targetHeight = rowMaxHeights[rowIndex] Column( modifier = Modifier .then(if (targetHeight != null) Modifier.height(targetHeight.dp) else Modifier) .fillMaxWidth() ) { Image( painter = painterResource(id = item.imageRes), contentDescription = null, modifier = Modifier.fillMaxWidth().aspectRatio(1f) ) Text(text = item.text, modifier = Modifier.padding(top = 8.dp)) } } } } data class Item(val imageRes: Int, val text: String)
方案二:使用SubcomposeLayout自定义等高网格
SubcomposeLayout允许先预测量所有子项的尺寸,再根据测量结果进行布局,能精准实现行内项等高,且不会产生多余内边距。
@Composable fun EqualHeightGrid( columns: Int, items: List<Item>, modifier: Modifier = Modifier, rowSpacing: Dp = 8.dp ) { val rowSpacingPx = rowSpacing.toPx() SubcomposeLayout(modifier) { constraints -> val itemWidth = constraints.maxWidth / columns val itemConstraints = constraints.copy(minWidth = itemWidth) // 第一步:预测量所有项的高度 val itemHeights = items.map { item -> subcompose("pre-measure-$item") { GridItem(item = item) }.first().measure(itemConstraints).height } // 按行分组计算每行最大高度 val rowMaxHeights = itemHeights.chunked(columns).map { it.max() } // 计算整体布局高度 val totalHeight = rowMaxHeights.sum() + (rowMaxHeights.size - 1) * rowSpacingPx.toInt() // 第二步:实际布局每个项 layout(constraints.maxWidth, totalHeight) { items.forEachIndexed { index, item -> val row = index / columns val column = index % columns val targetHeight = rowMaxHeights[row] val placeable = subcompose("layout-$item") { GridItem(item = item) }.first().measure(itemConstraints.copy(minHeight = targetHeight)) val xOffset = column * itemWidth val yOffset = rowMaxHeights.take(row).sum() + (row * rowSpacingPx).toInt() placeable.place(x = xOffset, y = yOffset) } } } } @Composable private fun GridItem(item: Item) { Column(modifier = Modifier.fillMaxWidth()) { Image( painter = painterResource(id = item.imageRes), contentDescription = null, modifier = Modifier.fillMaxWidth().aspectRatio(1f) ) Text(text = item.text, modifier = Modifier.padding(top = 8.dp)) } }
内容的提问来源于stack exchange,提问作者SmallGrammer
相关产品推荐
相关产品推荐

