Android Compose:LazyVerticalGrid多列滑动删除异常问题咨询
问题
在最新的Android Compose项目中,原本运行正常的LazyColumn滑动删除(swipe to dismiss)功能,在重构替换为LazyVerticalGrid后,仅滑动删除出现异常:
- 单列模式下LazyVerticalGrid的滑动删除可正常工作
- 切换为多列模式时,滑动item会抛出如下异常:
Process: com.elsevier.practiceupdate, PID: 23783 java.lang.IllegalArgumentException: Failed requirement. at androidx.compose.foundation.lazy.grid.LazyGridSpanLayoutProvider.getLineIndexOfItem--_Ze7BM(LazyGridSpanLayoutProvider.kt:174) at androidx.compose.foundation.lazy.grid.LazyGridItemPlacementAnimatorKt.lastIndexInPreviousLineBefore(LazyGridItemPlacementAnimator.kt:489) at androidx.compose.foundation.lazy.grid.LazyGridItemPlacementAnimatorKt.access$lastIndexInPreviousLineBefore(LazyGridItemPlacementAnimator.kt:1) at androidx.compose.foundation.lazy.grid.LazyGridItemPlacementAnimator.calculateExpectedOffset-xfIKQeg(LazyGridItemPlacementAnimator.kt:370) at androidx.compose.foundation.lazy.grid.LazyGridItemPlacementAnimator.onMeasured(LazyGridItemPlacementAnimator.kt:160) at androidx.compose.foundation.lazy.grid.LazyGridMeasureKt.measureLazyGrid-0cYbdkg(LazyGridMeasure.kt:241) at androidx.compose.foundation.lazy.grid.LazyGridKt$rememberLazyGridMeasurePolicy$1$1.invoke-0kLqBqw(LazyGrid.kt:334) at androidx.compose.foundation.lazy.grid.LazyGridKt$rememberLazyGridMeasurePolicy$1$1.invoke(LazyGrid.kt:184) at androidx.compose.foundation.lazy.layout.LazyLayoutKt$LazyLayout$1$2$1.invoke-0kLqBqw(LazyLayout.kt:71) at androidx.compose.foundation.lazy.layout.LazyLayoutKt$LazyLayout$1$2$1.invoke(LazyLayout.kt:69) at androidx.compose.ui.layout.LayoutNodeSubcompositionsState$createMeasurePolicy$1.measure-3p2s80s(SubcomposeLayout.kt:591) at androidx.compose.ui.node.InnerNodeCoordinator.measure-BRTryo0(InnerNodeCoordinator.kt:103) at androidx.compose.foundation.AndroidOverscrollKt$StretchOverscrollNonClippingLayer$2.invoke-3p2s80s(AndroidOverscroll.kt:578) at androidx.compose.foundation.AndroidOverscrollKt$StretchOverscrollNonClippingLayer$2.invoke(AndroidOverscroll.kt:577) at androidx.compose.ui.layout.LayoutModifierImpl.measure-3p2s80s(LayoutModifier.kt:285) at androidx.compose.ui.node.BackwardsCompatNode.measure-3p2s80s(BackwardsCompatNode.kt:343) at androidx.compose.ui.node.LayoutModifierNodeCoordinator.measure-BRTryo0(LayoutModifierNodeCoordinator.kt:155) at androidx.compose.foundation.AndroidOverscrollKt$StretchOverscrollNonClippingLayer$1.invoke-3p2s80s(AndroidOverscroll.kt:562) at androidx.compose.foundation.AndroidOverscrollKt$StretchOverscrollNonClippingLayer$1.invoke(AndroidOverscroll.kt:561) at androidx.compose.ui.layout.LayoutModifierImpl.measure-3p2s80s(LayoutModifier.kt:285) at androidx.compose.ui.node.BackwardsCompatNode.measure-3p2s80s(BackwardsCompatNode.kt:343) at androidx.compose.ui.node.LayoutModifierNodeCoordinator.measure-BRTryo0(LayoutModifierNodeCoordinator.kt:155) at androidx.compose.ui.graphics.SimpleGraphicsLayerModifier.measure-3p2s80s(GraphicsLayerModifier.kt:578) at androidx.compose.ui.node.BackwardsCompatNode.measure-3p2s80s(BackwardsCompatNode.kt:343) at androidx.compose.ui.node.LayoutModifierNodeCoordinator.measure-BRTryo0(LayoutModifierNodeCoordinator.kt:155) at androidx.compose.ui.node.LayoutNodeLayoutDelegate$performMeasure$2.invoke(LayoutNodeLayoutDelegate.kt:1090) at androidx.compose.ui.node.LayoutNodeLayoutDelegate$performMeasure$2.invoke(LayoutNodeLayoutDelegate.kt:1086) at androidx.compose.runtime.snapshots.Snapshot$Companion.observe(Snapshot.kt:2139) at androidx.compose.runtime.snapshots.SnapshotStateObserver$observeReads$1$1.invoke(SnapshotStateObserver.kt:130) at androidx.compose.runtime.snapshots.SnapshotStateObserver$observeReads$1$1.invoke(SnapshotStateObserver.kt:126) at androidx.compose.runtime.SnapshotStateKt__DerivedStateKt.observeDerivedStateRecalculations(DerivedState.kt:341) at androidx.compose.runtime.SnapshotStateKt.observeDerivedStateRecalculations(Unknown Source:1) at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:126) at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui_release(OwnerSnapshotObserver.kt:120) at androidx.compose.ui.node.OwnerSnapshotObserver.observeMeasureSnapshotReads$ui_release(OwnerSnapshotObserver.kt:107)
请问多列模式的LazyVerticalGrid是否支持滑动删除功能?
回答
多列模式的LazyVerticalGrid本身支持滑动删除功能,你遇到的异常是Compose特定版本的布局动画bug导致的,并非功能不支持。
异常原因
从栈追踪可以看出,问题出在LazyGridSpanLayoutProvider.getLineIndexOfItem的参数校验失败。多列模式下,当删除item后,LazyGrid的内置布局动画在计算剩余item的位置时,错误引用了已被移除的item索引,触发了非法参数异常。
解决方案
临时规避动画bug:禁用LazyVerticalGrid的item动画,通过自定义LazyGridState实现:
val gridState = rememberLazyGridState(animationSpec = null) LazyVerticalGrid( state = gridState, columns = GridCells.Fixed(2), // 其他参数 ) { // 列表项内容 }这种方式会关闭删除后的item位移动画,但能避免崩溃。
升级Compose版本:这个bug在Compose Foundation 1.4.0及以上的稳定版本中已经被修复,升级项目的Compose依赖到最新稳定版即可彻底解决问题。
自定义滑动删除逻辑:如果暂时无法升级依赖,可以放弃官方的
swipeToDismiss,使用Modifier.dragGestureFilter实现自定义滑动逻辑,删除时直接更新列表数据源,不依赖LazyGrid的内置动画。
内容的提问来源于stack exchange,提问作者Hector
相关产品推荐
相关产品推荐

