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

Jetpack Compose BottomSheetScaffold中LazyColumn过度渲染占用额外空间问题

Jetpack Compose BottomSheet内LazyColumn过度渲染问题解决

问题场景

使用Jetpack Compose开发Android应用,先后尝试了Morfly Advanced Bottom Sheet(基于Material3 BottomSheetScaffold实现)和官方Material3 BottomSheetScaffold,均遇到同一问题:底部弹窗内的LazyColumn会渲染远超可见区域的列表项。实际屏幕仅能显示5个可见项,但通过scrollState.layoutInfo.visibleItemsInfo日志排查发现,已有17个项被提前渲染,引发性能问题。

尝试过调整修饰符、高度约束均无效;给LazyColumn设置固定尺寸可解决过度渲染,但会导致底部弹窗无法按需展开。

原代码如下:

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun LeagueScreen(viewModel: LeagueScreenViewModel) {
    val scrollState = rememberLazyListState()
    val tops = UtilsKt.getMockTops(20)

    LaunchedEffect(scrollState) {
        snapshotFlow { scrollState.layoutInfo.visibleItemsInfo }
            .distinctUntilChanged()
            .collect { visibleItems ->
                Utils.log("visibleItemIndices: ${visibleItems.map { it.key }}")
            }
    }

    val scaffoldState = io.morfly.compose.bottomsheet.material3.rememberBottomSheetScaffoldState()

    io.morfly.compose.bottomsheet.material3.BottomSheetScaffold(
        sheetShape = RoundedCornerShape(16.dp),
        scaffoldState = scaffoldState,
        sheetContent = {
            LazyColumn(
                modifier = Modifier.fillMaxWidth(),
                state = scrollState
            ) {
                items(count = tops.size) { index ->
                    PeopleOnLeagueItem(
                        item = tops[index],
                        onItemClick = { },
                        modifier = Modifier
                    )
                }
            }
        },
        content = {}
    )
}

问题原因

BottomSheetScaffold的sheetContent默认会向父布局请求最大可用高度,即使BottomSheet处于部分展开状态,布局测量阶段仍会按照全展开的高度来计算。LazyColumn在没有明确的最大高度约束时,会基于这个最大可用高度预渲染大量列表项,导致过度渲染。

解决方案

通过动态约束LazyColumn的最大高度,使其与BottomSheet当前的实际可见高度保持一致,这样LazyColumn只会渲染当前可见区域内(及少量预加载)的项,同时不影响BottomSheet的按需展开功能。

修改后的代码

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun LeagueScreen(viewModel: LeagueScreenViewModel) {
    val scrollState = rememberLazyListState()
    val tops = UtilsKt.getMockTops(20)
    val scaffoldState = io.morfly.compose.bottomsheet.material3.rememberBottomSheetScaffoldState()
    // 存储BottomSheet当前的实际高度
    val currentSheetHeight = remember { mutableStateOf(0.dp) }

    LaunchedEffect(scrollState) {
        snapshotFlow { scrollState.layoutInfo.visibleItemsInfo }
            .distinctUntilChanged()
            .collect { visibleItems ->
                Utils.log("visibleItemIndices: ${visibleItems.map { it.key }}")
            }
    }

    io.morfly.compose.bottomsheet.material3.BottomSheetScaffold(
        sheetShape = RoundedCornerShape(16.dp),
        scaffoldState = scaffoldState,
        sheetContent = {
            Box(
                modifier = Modifier
                    .fillMaxWidth()
                    // 监听BottomSheet的实际绘制尺寸,更新高度
                    .onSizeChanged { size ->
                        currentSheetHeight.value = size.height.toDp()
                    }
            ) {
                LazyColumn(
                    modifier = Modifier
                        .fillMaxWidth()
                        // 动态约束LazyColumn的最大高度
                        .heightIn(max = currentSheetHeight.value),
                    state = scrollState
                ) {
                    items(count = tops.size) { index ->
                        PeopleOnLeagueItem(
                            item = tops[index],
                            onItemClick = { },
                            modifier = Modifier
                        )
                    }
                }
            }
        },
        content = {}
    )
}

关键说明

  1. 动态高度约束:通过Box的onSizeChanged监听BottomSheet的实际绘制高度,实时更新currentSheetHeight,再用heightIn(max = currentSheetHeight.value)约束LazyColumn的最大高度,确保LazyColumn仅基于当前可见高度计算渲染项。
  2. 兼容性:如果切换到官方Material3的BottomSheetScaffold,只需替换对应的包名(将io.morfly.compose.bottomsheet.material3改为androidx.compose.material3),代码逻辑完全通用。
  3. 性能保障:这种方式既保留了BottomSheet按需展开的特性,又避免了LazyColumn过度渲染,同时onSizeChanged的开销极低,不会影响整体性能。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 12:44:57