ViewPager2内嵌Compose LazyList出现同方向滚动嵌套异常如何解决
问题根因
你的动态适配ViewPager2高度的逻辑会导致内部ComposeView经历两次测量:
- 第一次测量时你传入了
UNSPECIFIED的高度约束,此时LazyColumn会拿到无限高度的测量条件,默认不会开启滚动能力,会测量所有子项得到总内容高度 - 你把ViewPager2的高度硬设为测量得到的总高度后,ComposeView会触发二次测量,此时拿到的是
EXACTLY的固定高度约束。如果LazyColumn的总内容高度大于该固定高度(通常是因为超过了BottomSheet的最大可用高度),LazyColumn会自动开启垂直滚动能力,而BottomSheet本身也支持同方向的垂直滚动,会被Compose的滚动检测器判定为非法的同方向嵌套滚动,触发异常。
解决方案
根据你的产品需求选择对应方案即可:
方案1:ViewPager2高度完全适配内容,由BottomSheet处理整体滚动
如果你的产品逻辑是让整个BottomSheet滚动,内部LazyColumn不需要自行滚动:
- 给LazyColumn(或其他带
verticalScroll修饰符的组件)做两处修改:- 用
Modifier.wrapContentHeight()替代fillMaxHeight/固定高度配置 - 添加
userScrollEnabled = false参数关闭自身滚动能力
- 用
- 可选优化:如果LazyColumn内容过长,建议主动限制BottomSheet的最大高度,避免内容超出屏幕无法查看。
方案2:LazyColumn自行处理滚动,ViewPager2高度固定
如果你的产品逻辑是让LazyColumn在固定高度内滚动,不需要ViewPager2适配内容高度:
- 移除你写的
AdaptChildHeightOnPageChange动态高度适配逻辑 - 给ViewPager2设置高度为
match_parent,或者你需要的固定高度 - 按需调整BottomSheet的
peekHeight即可,此时LazyColumn会拿到稳定的固定高度约束,正常开启自身滚动,不会触发嵌套滚动异常。
附加优化建议
如果保留动态高度适配逻辑,建议在页面销毁时主动移除所有GlobalLayoutListener和未执行的post任务,避免内存泄漏。
内容的提问来源于stack exchange,提问作者Thomas Keller
相关产品推荐
相关产品推荐

