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

LazyColumn删除非末尾项时SwipeToDismiss出现异常行为

问题解决:LazyColumn中SwipeToDismiss删除非末尾项滑动异常

问题现象

在Jetpack Compose的LazyColumn中实现SwipeToDismiss交互时,删除最后一项或唯一一项功能正常,但删除非末尾项时,下一项会向起始方向滑动,却无法完全滑出屏幕。

问题原因

直接在items内部创建rememberDismissState时,列表项因删除操作重新组合后,新的列表项会复用被删除项的dismissState状态,导致状态混乱,引发滑动异常。

解决方案

为每个列表项的dismissState绑定唯一标识(比如任务ID),确保每个项的状态独立,避免复用。

修改后的代码

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun TasksListLayout(
    modifier: Modifier = Modifier,
    onNavigate: (UiEvent.Navigate) -> Unit,
    viewModel: TaskViewModel = hiltViewModel()
) {
    val tasks = viewModel.tasks.collectAsState(initial = emptyList())
    val snackbarHostState = remember { SnackbarHostState() }
    val scope = rememberCoroutineScope()
    LaunchedEffect(key1 = true) {
        viewModel.uiEvent.collect { event ->
            when (event) {
                is UiEvent.ShowSnackbar -> {
                    val result = scope.launch {
                        snackbarHostState.showSnackbar(
                            message = event.message, actionLabel = event.action, duration = SnackbarDuration.Long
                        )
                    }
                    if (result.equals(SnackbarResult.ActionPerformed)) {
                        viewModel.onEvent(TaskListEvent.OnUndoDeleteTask)
                    }
                }
                is UiEvent.Navigate -> onNavigate(event)
                else -> Unit
            }
        }
    }
    Scaffold(
        snackbarHost = { SnackbarHost(snackbarHostState) },
        floatingActionButton = {
            FloatingActionButton(
                onClick = { viewModel.onEvent(TaskListEvent.OnAddTask) },
                containerColor = MaterialTheme.colorScheme.primary,
                contentColor = MaterialTheme.colorScheme.background
            ) {
                Icon(imageVector = Icons.Default.Add, contentDescription = "Add a task")
            }
        },
        topBar = {
            TopAppBar(
                title = { Text("Planner") }, colors = TopAppBarDefaults.topAppBarColors(
                    containerColor = MaterialTheme.colorScheme.primary,
                    titleContentColor = MaterialTheme.colorScheme.background
                )
            )
        },
    ) { padding ->
        LazyColumn(
            modifier = modifier
                .fillMaxSize()
                .padding(padding)
                .padding(horizontal = 12.dp),
            verticalArrangement = spacedBy(12.dp),
            contentPadding = PaddingValues(vertical = 12.dp)
        ) {
            items(tasks.value) { task ->
                // 绑定唯一ID作为状态键,确保每个项的滑动状态独立
                val dismissState = remember(key1 = task.id) {
                    DismissState(initialValue = DismissValue.Default)
                }
                SwipeToDismiss(
                    state = dismissState,
                    directions = setOf(DismissDirection.EndToStart),
                    confirmValueChange = {
                        if (it == DismissValue.DismissedToStart) {
                            viewModel.onEvent(TaskListEvent.OnDeleteTask(task))
                        }
                        true
                    },
                    background = { },
                    dismissContent = {
                        TaskCard(
                            task = task,
                            onEvent = viewModel::onEvent,
                            modifier = modifier
                        )
                    }
                )
            }
        }
    }
}

说明

  • 通过remember(key1 = task.id)创建DismissState,利用任务的唯一ID确保每个列表项的滑动状态不会被其他项复用。
  • 移除了rememberUpdatedState,因为状态已经通过唯一键隔离,直接使用当前task即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 14:45:33