ModalNavigationDrawer点击抽屉项后无法跳转页面的问题排查
问题描述
使用Jetpack Compose的ModalNavigationDrawer组件时,点击Drawer内的菜单项目后,页面没有触发跳转逻辑。以下是相关代码片段:
TaskListEvent.kt
sealed class TaskListEvent { data class OnDeleteTask(val task: Task) : TaskListEvent() object OnUndoDeleteTask : TaskListEvent() data class OnEditClick(val task: Task) : TaskListEvent() object OnAddTask : TaskListEvent() class OnDrawerNavigationClick(val navigationItem: NavigationItem) : TaskListEvent() }
Routes.kt
sealed class Routes(val route: String) { object TASKSLIST : Routes(route = "tasks_list") object ADDEDITTASK : Routes(route = "add_edit_task") }
Navigation.kt
@RequiresApi(Build.VERSION_CODES.TIRAMISU) @Composable fun Navigation(navController: NavHostController) { NavHost(navController = navController, startDestination = Routes.TASKSLIST.route) { composable( Routes.TASKSLIST.route ) { TasksListScreen(onNavigate = { navController.navigate(it.route) }) } composable( route = Routes.ADDEDITTASK.route + "?taskId={taskId}", arguments = listOf(navArgument(name = "taskId") { type = NavType.IntType defaultValue = -1 }) ) { AddEditScreen( onPopBackStack = { navController.popBackStack() }) } } }
NavigationItem.kt
data class NavigationItem( val title: String, val selectedIcon: ImageVector, val unselectedIcon: ImageVector, val route: String ) val items = listOf( NavigationItem( title = "Planner", selectedIcon = Icons.Default.Done, unselectedIcon = Icons.Default.Done, route = Routes.TASKSLIST.route ), NavigationItem( title = "Library", selectedIcon = Icons.Default.Email, unselectedIcon = Icons.Default.Email, route = Routes.ADDEDITTASK.route ) )
TaskListViewModel.kt
@HiltViewModel class TaskListViewModel @Inject constructor(private val repository: TaskRepositoryImplementation) : ViewModel() { // 省略其他代码... fun onEvent(event: TaskListEvent) { when(event) { // 其他事件处理... is TaskListEvent.OnDrawerNavigationClick -> { sendUiEvent(UiEvent.Navigate(event.navigationItem.route)) } } } private fun sendUiEvent(event: UiEvent) { viewModelScope.launch(Dispatchers.IO) { _uiEvent.send(event) } } }
TasksList.kt
@RequiresApi(Build.VERSION_CODES.TIRAMISU) @OptIn(ExperimentalMaterial3Api::class) @Composable fun TasksListScreen( modifier: Modifier = Modifier, onNavigate: (UiEvent.Navigate) -> Unit, viewModel: TaskListViewModel = hiltViewModel() ) { val tasks = viewModel.tasks.collectAsState(initial = emptyList()) val snackbarHostState = remember { SnackbarHostState() } val coroutineScope = rememberCoroutineScope() val snackBarController = SnackBarController(coroutineScope) LaunchedEffect(key1 = true) { viewModel.uiEvent.collectLatest { event -> when (event) { // 省略其他事件处理... is UiEvent.Navigate -> { onNavigate(event) } else -> Unit } } } val drawerState = rememberDrawerState(initialValue = DrawerValue.Closed) var selectedItemIndex by rememberSaveable { mutableIntStateOf(0) } ModalNavigationDrawer(drawerContent = { ModalDrawerSheet { items.forEachIndexed { index, item -> Spacer(modifier = Modifier.height(12.dp)) NavigationDrawerItem( label = { Text(item.title) }, selected = index == selectedItemIndex, onClick = { TaskListEvent.OnDrawerNavigationClick(item) selectedItemIndex = index coroutineScope.launch { drawerState.close() } }, icon = { Icon( imageVector = if (index == selectedItemIndex) { item.selectedIcon } else item.unselectedIcon, contentDescription = item.title ) }, modifier = Modifier.padding(NavigationDrawerItemDefaults.ItemPadding)) } } }, drawerState = drawerState) { // 省略页面主体代码... } }
问题原因
核心问题出在TasksList.kt的NavigationDrawerItem的onClick回调中:你只是创建了TaskListEvent.OnDrawerNavigationClick(item)事件对象,但没有将该事件传递给ViewModel的事件处理方法(比如onEvent),导致ViewModel无法触发后续的导航逻辑。
解决方案
- 修改
TasksList.kt中的onClick回调,调用ViewModel的onEvent方法发送事件:
onClick = { viewModel.onEvent(TaskListEvent.OnDrawerNavigationClick(item)) // 关键:将事件传递给ViewModel selectedItemIndex = index coroutineScope.launch { drawerState.close() } },
- 额外检查点:
- 确保
UiEvent.Navigate数据类正确定义,持有路由字符串:sealed class UiEvent { data class Navigate(val route: String) : UiEvent() // 其他事件... } - 跳转到
ADDEDITTASK路由时,因为该路由注册时带有taskId参数(默认值-1),当前NavigationItem中的route为"add_edit_task",由于参数有默认值,导航会正常工作;如果需要显式传参,可以将NavigationItem的route改为"add_edit_task?taskId=-1",或者在ViewModel中拼接参数后再发送导航事件。
- 确保
内容的提问来源于stack exchange,提问作者Juncu
相关产品推荐
相关产品推荐

