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

如何在Jetpack Compose中清除导航抽屉的历史选中项

问题原因

每个DrawerItem组件内部都单独维护了selectedItemIndex状态,这些状态互相独立。点击一个菜单项时,只会更新当前组件内的选中状态,其他DrawerItem的状态不会同步变化,因此出现多个项同时高亮的情况。

解决方法

把选中状态提升到所有DrawerItem的父组件中,让所有菜单项共享同一个选中状态。点击任何一项时,父组件更新选中值,所有DrawerItem都会根据这个统一值判断自己是否该高亮。

修改步骤

  1. 在父组件中维护全局选中状态:
// 父组件示例(包含导航抽屉的页面)
@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 // 点击时更新全局选中状态
                    // 其他业务逻辑
                }
            )
        }
    }
}
  1. 修改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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 11:24:56