如何在Jetpack Compose中清除导航抽屉的历史选中项
问题原因
每个DrawerItem组件内部都单独维护了selectedItemIndex状态,这些状态互相独立。点击一个菜单项时,只会更新当前组件内的选中状态,其他DrawerItem的状态不会同步变化,因此出现多个项同时高亮的情况。
解决方法
把选中状态提升到所有DrawerItem的父组件中,让所有菜单项共享同一个选中状态。点击任何一项时,父组件更新选中值,所有DrawerItem都会根据这个统一值判断自己是否该高亮。
修改步骤
- 在父组件中维护全局选中状态:
// 父组件示例(包含导航抽屉的页面) @Composable fun MailDrawer(navigationState: DrawerState) { // 全局维护选中的文件夹名称 var selectedFolder by rememberSaveable { mutableStateOf("") } val folderList = // 你的文件夹列表数据源 Column { folderList.forEach { folderItem -> DrawerItem( folderItem = folderItem, index = folderList.indexOf(folderItem), navigationState = navigationState, selectedFolder = selectedFolder, // 传递全局选中状态 onMenuClick = { folderName -> selectedFolder = folderName // 点击时更新全局选中状态 // 其他业务逻辑 } ) } } }
- 修改
DrawerItem组件,移除内部的selectedItemIndex,改为接收外部传入的选中状态:
@Composable fun DrawerItem( folderItem: NewFolderTableData, index: Int, navigationState: DrawerState, submenuList: ImmutableList<NewFolderTableData> = emptyList<NewFolderTableData>().toImmutableList(), selectedFolder: String, // 新增:接收父组件传入的选中状态 onMenuClick: (String)->Unit ) { val scope = rememberCoroutineScope() var showMoreSubMenu by rememberSaveable { mutableStateOf(false) } var showInboxSubMenu by rememberSaveable { mutableStateOf(false) } val title = if (folderItem.foldername == Const.MailFolder.TYPE_FOLDER_MAIL_SHOW_MORE) { if (!showMoreSubMenu) { Const.MailFolder.TYPE_FOLDER_MAIL_SHOW_MORE } else { Const.MailFolder.TYPE_FOLDER_MAIL_HIDE_MORE } } else { folderItem.foldername } NavigationDrawerItem(label = { Text(text = title) }, // 用全局选中状态判断是否高亮 selected = title == selectedFolder, onClick = { onMenuClick(folderItem.foldername) if (folderItem.foldername == Const.MailFolder.TYPE_FOLDER_MAIL_SHOW_MORE) { showMoreSubMenu = !showMoreSubMenu } else { scope.launch { navigationState.close() } } }, icon = { val iconId = getFolderIcons(folderItem.foldername) if (iconId != -1) { Image( painterResource(id = iconId), contentDescription = folderItem.foldername ) } }, badge = { if (folderItem.foldername.equals( Const.MailFolder.TYPE_FOLDER_MAIL_SHOW_MORE, ignoreCase = true ) ) { if (!showMoreSubMenu) { SetRightIcon(vector = Icons.Outlined.KeyboardArrowDown, foldername = folderItem.foldername){ } } else { SetRightIcon(vector = Icons.Outlined.KeyboardArrowUp, foldername = folderItem.foldername){ } } } else if (folderItem.foldername.equals( Const.MailFolder.TYPE_FOLDER_MAIL_INBOX, ignoreCase = true ) && submenuList.isNotEmpty() ) { if(!showInboxSubMenu){ SetRightIcon(vector = Icons.Outlined.KeyboardArrowDown, foldername = folderItem.foldername){ showInboxSubMenu = !showInboxSubMenu } }else{ SetRightIcon(vector = Icons.Outlined.KeyboardArrowUp, foldername = folderItem.foldername){ showInboxSubMenu = !showInboxSubMenu } } } else if (folderItem.foldername.equals( Const.MailFolder.TYPE_FOLDER_MAIL_TRASH, ignoreCase = true ) || folderItem.foldername.equals( Const.MailFolder.TYPE_FOLDER_MAIL_JUNK, ignoreCase = true ) ) { SetRightIcon(vector = Icons.Filled.Delete, foldername = folderItem.foldername){ } }else if(folderItem.foldername.equals(Const.MailFolder.TYPE_FOLDER_MAIL_ADD, ignoreCase = true)){ SetRightIcon(vector = Icons.Filled.Add, foldername = folderItem.foldername){ } } }, modifier = Modifier.padding(NavigationDrawerItemDefaults.ItemPadding) ) AnimatedVisibility(visible = showMoreSubMenu || showInboxSubMenu) { DrawSubMenu(subList = submenuList, navigationState) } }
关键改动说明
- 移除
DrawerItem内部的selectedItemIndex状态,改为从父组件接收selectedFolder参数 NavigationDrawerItem的selected判断条件改为使用全局的selectedFolder- 点击菜单项时,不再更新
DrawerItem内部状态,而是通过onMenuClick通知父组件更新全局选中值
这样所有菜单项都会基于同一个全局状态判断是否高亮,自然就不会出现多个项同时选中的问题了。
内容的提问来源于stack exchange,提问作者Ashish singh
相关产品推荐
相关产品推荐

