Jetpack Compose 中如何让嵌套 Column 自适应高度并支持滚动?
可以给内部 Column 设置 Modifier.weight(1f),让它占据外层 Column 的剩余高度,再使用 verticalScroll()。外层布局需要有有限的高度约束,例如屏幕内容区域的高度。
不必固定为 250.dp,但滚动区域仍需要有限的可视高度。
为什么去掉固定高度后会出问题?
问题中的代码通过以下方式限定滚动区域:
Modifier
.height(250.dp)
.verticalScroll(rememberScrollState())
这里的 height(250.dp) 为滚动区域指定了可视高度,超出这个高度的内容可以滚动。
去掉固定高度后,滚动能否正常工作取决于父布局传递的约束。内部 Column 嵌套在另一个 Column 中,不会自动占据剩余空间。如果它没有获得有限的高度上限,就无法正常垂直滚动;如果它占用了其他内容需要的空间,底部内容也可能被挤出可视区域。
需要根据外层的可用高度为它分配空间。
使用 weight 分配剩余高度
下面的示例保留顶部和底部内容,让中间的 Column 使用剩余高度:
@Composable
fun ResponsiveScrollableColumn(items: List<String>) {
val scrollState = rememberScrollState()
Column(
modifier = Modifier.fillMaxSize()
) {
Text(
text = "顶部内容",
modifier = Modifier.padding(16.dp)
)
Column(
modifier = Modifier
.weight(1f)
.fillMaxWidth()
.verticalScroll(scrollState)
.padding(horizontal = 16.dp)
) {
items.forEach { item ->
Text(
text = item,
modifier = Modifier.padding(vertical = 8.dp)
)
}
}
Text(
text = "底部内容",
modifier = Modifier.padding(16.dp)
)
}
}
将组件放在高度有限的屏幕内容区域中。外层 Column 会先测量未设置权重的顶部和底部内容,再将剩余高度分配给设置了 weight(1f) 的内部 Column。
屏幕尺寸或外层可用空间变化时,中间区域的高度会随之调整。内容超出该区域时,可以在其中滚动。
weight(1f) 默认会填满分配到的高度。如果希望内容较少时只占实际需要的高度,可以按布局需要使用 weight(1f, fill = false);这样也会改变底部内容的位置。
父级必须提供有限高度
这个方案要求外层有有限的可用高度。示例中的 fillMaxSize() 使用父级允许的空间,本身不能将无限高度转换为有限高度。
以下情况需要注意:
- 外层
Column也使用了verticalScroll()。 - 组件位于
LazyColumn的某个 item 内,沿垂直方向获得无界测量约束。 - 更上层的自定义布局没有提供有限的最大高度。
这些情况下,weight 无法正常计算“剩余高度”。垂直滚动容器在测量时收到无限的最大高度,还可能抛出约束相关异常。
先确定滚动范围:如果顶部、列表和底部需要一起滚动,可以让它们共用一个滚动容器;如果只让中间区域滚动,则需保持外层高度有限,并将滚动行为放在中间区域。
内容很多时使用 LazyColumn
如果内部主要用于展示大量列表项,可以将内部 Column 替换为 LazyColumn,同样通过 weight(1f) 分配剩余高度:
@Composable
fun ResponsiveLazyList(entries: List<String>) {
Column(modifier = Modifier.fillMaxSize()) {
Text(
text = "顶部内容",
modifier = Modifier.padding(16.dp)
)
LazyColumn(
modifier = Modifier
.weight(1f)
.fillMaxWidth(),
contentPadding = PaddingValues(horizontal = 16.dp)
) {
items(entries) { entry ->
Text(
text = entry,
modifier = Modifier.padding(vertical = 8.dp)
)
}
}
Text(
text = "底部内容",
modifier = Modifier.padding(16.dp)
)
}
}
LazyColumn 自带垂直滚动能力,无需再添加 verticalScroll()。少量、结构固定的内容可以使用 Column 配合 verticalScroll();较长列表通常更适合使用 LazyColumn,避免一次组合和测量所有列表项。
备注:内容仅供参考。
