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
相关产品推荐
相关产品推荐

