Jetpack Compose动态计算Spacer高度解决LazyRow布局跳动问题
Jetpack Compose LazyRow 滚动导致下方布局跳动解决方案
问题核心:LazyRow作为懒加载容器,初始测量时仅会基于可见范围内的子项计算自身高度,当滚动到包含更高多行文本的子项时,LazyRow整体高度会动态变大,推挤下方布局产生肉眼可见的跳动,固定LazyRow高度会导致短文本子项留白过多的问题。
解法1:预计算所有子项的最大高度,设置LazyRow最小高度
该方案从根源避免高度变化,提前测量所有子项中文本部分的最大高度,加上固定的图片高度作为LazyRow的最小高度,既不会出现多余留白,也不会出现高度动态变化。
示例代码:
import androidx.compose.ui.text.Paragraph import androidx.compose.ui.text.TextStyle import androidx.compose.ui.unit.Constraints Column { topicList.forEach { topic -> val showList: List<Show> = topic.shows // 上下文和文本样式需和实际Text组件使用的样式完全一致 val context = LocalContext.current val titleStyle = MaterialTheme.typography.subtitle1 val infoStyle = MaterialTheme.typography.caption // 预计算所有子项的文本总高度,取最大值 val maxTextHeight = remember(showList, titleStyle, infoStyle) { showList.maxOf { show -> // 测量title高度,maxWidth为子项固定宽度,按需修改 val titleParagraph = Paragraph( text = show.title, style = titleStyle, constraints = Constraints(maxWidth = 120.dp.roundToPx()), density = context.resources.displayMetrics.density, resourceLoader = context.resources ) // 测量info高度 val infoParagraph = Paragraph( text = show.info, style = infoStyle, constraints = Constraints(maxWidth = 120.dp.roundToPx()), density = context.resources.displayMetrics.density, resourceLoader = context.resources ) titleParagraph.height + infoParagraph.height }.toDp() } // Image固定高度、子项内边距按需修改 val imageHeight = 180.dp val itemPadding = 8.dp val lazyRowMinHeight = imageHeight + maxTextHeight + itemPadding Column { Text(text = topic.title) // 给LazyRow设置最小高度,已覆盖最大可能值所以高度固定 LazyRow(modifier = Modifier.heightIn(min = lazyRowMinHeight)) { items(showList) { show -> Column(modifier = Modifier.padding(4.dp).width(120.dp)) { Image(modifier = Modifier.height(imageHeight).fillMaxWidth()) Text(text = show.title, style = titleStyle) Text(text = show.info, style = infoStyle) } } } Spacer(Modifier.height(32.dp)) } } }
解法2:统一LazyRow所有子项高度
如果接受所有子项高度和最高子项对齐,可以通过固有特性测量实现,代码更简单,适合子项宽度固定的场景:
LazyRow(modifier = Modifier.height(IntrinsicSize.Min)) { items(showList) { show -> Column(modifier = Modifier.height(IntrinsicSize.Max).width(120.dp)) { Image(modifier = Modifier.height(180.dp).fillMaxWidth()) Text(text = show.title) Text(text = show.info) } } }
解法3:动态记录最大高度,只扩展不收缩
如果不想提前预测量,可以动态记录LazyRow的最大高度,后续高度不会低于该最大值,仅第一次遇到更高子项时变化一次,配合动画几乎无感知:
Column { topicList.forEach { topic -> val showList: List<Show> = topic.shows // 记录LazyRow的最大高度 var maxLazyRowHeight by remember { mutableStateOf(0.dp) } Column { Text(text = topic.title) LazyRow( modifier = Modifier .heightIn(min = maxLazyRowHeight) .onSizeChanged { val currentHeight = it.height.toDp() if (currentHeight > maxLazyRowHeight) { maxLazyRowHeight = currentHeight } } // 添加高度动画弱化首次变化的感知 .animateContentSize() ) { items(showList) { show -> Column(modifier = Modifier.padding(4.dp).width(120.dp)) { Image(modifier = Modifier.height(180.dp).fillMaxWidth()) Text(text = show.title) Text(text = show.info) } } } Spacer(Modifier.height(32.dp)) } } }
内容的提问来源于stack exchange,提问作者Saehun Sean Oh
相关产品推荐
相关产品推荐

