Jetpack Compose实现垂直嵌套滚动及内部元素拖拽排序的方案咨询
Jetpack Compose 同方向嵌套滚动冲突解决方案
核心问题根源
你遇到的异常是Jetpack Compose的原生限制:
java.lang.IllegalStateException: Nesting scrollable in the same direction layouts like ScrollableContainer and LazyColumn is not allowed. If you want to add a header before the list of items please take a look on LazyColumn component which has a DSL api which allows to first add a header via item() function and then the list of items via items().
同方向的滚动容器嵌套会导致滚动手势歧义,官方明确禁止该用法。
可行解决方案
这里提供两种适配你业务场景的实现方式,都可以同时满足「页面整体滚动」+「组内动作拖拽重排」的需求:
方案1:单LazyColumn扁平化结构(性能最优)
将外层训练组卡片、组内训练动作都作为外层单个LazyColumn的独立条目,通过拖拽逻辑限制重排范围:
- 提前对所有条目打标,标记每个条目属于哪个训练组、是组头还是动作项
- 重写拖拽移动的判断逻辑,仅允许相同训练组内的动作项互相交换位置,跨组的拖拽操作直接拦截不生效
- 整个页面只有一个滚动容器,完全规避嵌套滚动冲突,同时Lazy的复用能力可以支撑大量训练组/动作的场景
方案2:禁用内层LazyColumn滚动(改造成本最低)
不需要改动现有业务结构,仅修改内层LazyColumn的配置即可:
- 给内层LazyColumn设置
userScrollEnabled = false禁用自身滚动能力 - 给内层LazyColumn添加
Modifier.wrapContentHeight()让高度自适应内容,所有动作项直接全部展开 - 外层LazyColumn负责整个页面的滚动,内层仅作为静态的动作列表容器,拖拽重排逻辑不受滚动禁用的影响,仍可正常完成组内重排
代码修改示例(基于方案2)
LazyColumn(Modifier.fillMaxSize()) { itemsIndexed(workout.workoutSets) { setIndex, workoutSet -> //State that contains the re-order drag & drop and calls the original list to be modified in my VM val state: ReorderableState = rememberReorderState(onMove = { from, to -> Grove.e { "Moving from $from to $to" } if (to <= workoutSet.exercises.lastIndex) { onExerciseMoved(setIndex, from, to) } }) LazyColumn( state = state.listState, // 核心修改点:禁用自身滚动+高度自适应内容 userScrollEnabled = false, modifier = Modifier .fillMaxWidth() .wrapContentHeight() .reorderable(state) //Modifier that allows the drad&drop in this container ) { itemsIndexed(items = workoutSet.exercises, itemContent = { index, item -> Box( Modifier .fillMaxWidth() .draggedItem(state.offset.takeIf { state.index == index }) //The dragged item modifier .scale(if (state.index == null || state.index == index) 1f else .9f) ) { CreatorExerciseItemRow( onExerciseClick = { onExerciseClick(item) }, execution = item ) } }) } } }
注意事项
如果单个训练组内的动作数量超过20项,更推荐使用方案1,避免内层LazyColumn全量渲染带来的性能损耗。
内容的提问来源于stack exchange,提问作者Francisco Durdin Garcia
相关产品推荐
相关产品推荐

