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

Jetpack Compose LazyColumn侧滑删除动画结束不流畅问题求助

解决Jetpack Compose LazyColumn滑动删除时卡片跳位问题

问题分析

你遇到的问题确实和LazyColumn的Arrangement.spacedBy(32.dp)有关。spacedBy的间距由LazyColumn统一管理,当你用AnimatedVisibility收缩删除的卡片时,间距并不会跟着动画消失——只有当数据从列表中移除后,LazyColumn才会瞬间移除对应的间距,这就导致了下方卡片突然跳位的现象。

要保留卡片间距同时解决动画问题,需要把间距从LazyColumn的全局设置转移到每个列表项的本地容器中,让间距和卡片一起参与动画。

修复步骤

  1. 移除LazyColumn的全局间距设置,删除verticalArrangement = Arrangement.spacedBy(32.dp)
  2. 给每个列表项添加本地间距,在SwipeToDeleteContainer内部给卡片包裹带底部间距的容器(最后一个item不加,避免多余间距)
  3. 调整动画范围,确保动画作用于包含间距的整个容器,而非仅卡片本身

修改后的代码

MainScreen.kt

修改LazyColumn部分,移除全局间距并改用itemsIndexed传递索引:

LazyColumn(
    contentPadding = PaddingValues(bottom = 10.dp, top = 10.dp),
    // 移除verticalArrangement = Arrangement.spacedBy(32.dp)
    modifier = Modifier.weight(10f)
) {
    itemsIndexed(
        items = state.tasks,
        key = { _, task -> task.id }
    ) { index, task ->
        SwipeToDeleteContainer(
            item = task,
            onDelete = {
                onEvent(TaskEvent.DeleteTask(task.id))
            },
            isLastItem = index == state.tasks.lastIndex
        ) {
            TaskCard(
                taskCardDto = task,
                onCheckedChange = { id, done -> onEvent(TaskEvent.SetDone(id, done)) }
            )
        }
    }
}

SwipeToDeleteContainer.kt

更新容器逻辑,添加间距参数并包裹带间距的容器:

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun <T> SwipeToDeleteContainer(
    item: T,
    onDelete: (T) -> Unit,
    animationDuration: Int = 500,
    isLastItem: Boolean = false, // 新增参数:判断是否为最后一项
    content: @Composable (T) -> Unit
) {
    var isRemoved by remember {
        mutableStateOf(false)
    }
    val state = rememberDismissState(
        confirmValueChange = { value ->
            if (value == DismissValue.DismissedToStart) {
                isRemoved = true
                true
            } else {
                false
            }
        }
    )

    LaunchedEffect(key1 = isRemoved) {
        if(isRemoved) {
            delay(animationDuration.toLong())
            onDelete(item)
        }
    }

    AnimatedVisibility(
        visible = !isRemoved,
        exit = shrinkVertically(
            animationSpec = tween(durationMillis = animationDuration),
            shrinkTowards = Alignment.Top
        ) + fadeOut()
    ) {
        // 包裹带间距的容器,最后一项不加底部间距
        Box(modifier = Modifier.padding(bottom = if (isLastItem) 0.dp else 32.dp)) {
            SwipeToDismiss(
                state = state,
                background = {
                    DeleteBackground(swipeDismissState = state)
                },
                dismissContent = { content(item) },
                directions = setOf(DismissDirection.EndToStart)
            )
        }
    }
}

TaskCard.kt & Constants.kt

这两个文件无需修改,保持原有逻辑即可。

原理说明

通过将间距从LazyColumn的全局设置转移到每个列表项的本地容器,删除动画时卡片和间距会一起收缩消失,LazyColumn的布局会平滑过渡,不会出现跳位现象。itemsIndexed用于判断最后一项,避免列表底部出现多余的间距。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 00:24:51