Search code examples
androidkotlinandroid-jetpack-composenavigation-drawerandroid-jetpack-compose-ui

How to clear previously selected items in Navigation Drawer (Jetpack Compose)


I have navigation drawer with multiple menu Items. When I click on any item it gets selected (Inbox) with highlighted color . After that if I click some other items (flagged Mail) it also gets selected with highlighted color . But previous selected (Inbox) should be cleared (highlighted color should be gone).

Only one item should be shown as Highlighted at a time . In my case both items are being highlighted as selected .ScreenShot

@Composable
fun DrawerItem(
  folderItem: NewFolderTableData,
  index: Int,
  navigationState: DrawerState,
  submenuList: ImmutableList<NewFolderTableData> = 
  emptyList<NewFolderTableData>().toImmutableList(),
  onMenuClick: (String)->Unit
) {

  val scope = rememberCoroutineScope()
  var selectedItemIndex by rememberSaveable {
    mutableStateOf("")
  }

  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 == selectedItemIndex, onClick = {
    onMenuClick(folderItem.foldername)
    if (folderItem.foldername == Const.MailFolder.TYPE_FOLDER_MAIL_SHOW_MORE) {
        showMoreSubMenu = !showMoreSubMenu
    } else {
        selectedItemIndex = title
        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)
  } 
}

Solution

  • The way you implemented it now, each DrawerItem has its own selectedItemIndex. Once you click the item, it will be highlighted. However, clicking one DrawerItem does not affect the local selectedItemIndex of all other DrawerItems.

    So you will have to move the selection logic into the parent Composable. When you click a DrawerItem, update the selected index in the parent Composable.
    You have not provided any code, but I will provide a generic example:

    // move this declaration from DrawerItem into here
    var selectedItemIndex by rememberSaveable {
        mutableStateOf("")
    }
    
    ModalNavigationDrawer(
        drawerContent = {
            ModalDrawerSheet {
                Text("My Drawer", modifier = Modifier.padding(16.dp))
                Divider()
                DrawerItem(
                    selectedItemIndex = selectedItemIndex,
                    updateSelectedItemIndex = { newItemIndex ->
                        selectedItemIndex = newItemIndex
                    },
                    //... other parameters
                )
                // ...other DrawerItem Composables
            }
        }
    ) {
        // Screen content
    }
    

    Now, update the signature of your DrawerItem Composable as follows:

    @Composable
    fun DrawerItem(
      selectedItemIndex: String,
      updateSelectedItemIndex: (String) -> Unit,
      // ... other parameters
    ) {
    
        //..
        onClick = {
            onMenuClick(folderItem.foldername)
            if (folderItem.foldername == Const.MailFolder.TYPE_FOLDER_MAIL_SHOW_MORE) {
                showMoreSubMenu = !showMoreSubMenu
            } else {
                updateSelectedItemIndex(title)  // invoke callback function to update selection in parent
                scope.launch {
                    navigationState.close()
                }
            }
        },
        //...
    }