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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 03:10:56