Search code examples
kotlindrop-down-menuandroid-jetpack-composeandroid-jetpack-navigation

Is it possible to use a dropdown menu as navigation?


I am trying to use a dropdown menu as my navigation for an app I am building. However I get an error inside the onClick function of the dropdown menu items saying "unsolved reference".

I have tried following this course but that way didn't work for me. It uses regular buttons to navigate, but i want to use a dropdown. I tried Googling the error and tried a few possible solutions but none of them worked for me.

Below is the code of the dropdown menu

@Composable
fun TopAppBarDropdownMenu() {
    val expanded = remember { mutableStateOf(false) }
    
    Box(
        Modifier
            .wrapContentSize(Alignment.TopEnd)
    ) {
        IconButton(
            onClick = {
                expanded.value = true
            }
        ) {
            Icon(
                Icons.Filled.Menu,
                contentDescription = "Menu"
            )
        }
    }

    DropdownMenu(
        expanded = expanded.value,
        onDismissRequest = { expanded.value = false}
    ) {
        DropdownMenuItem(
            text = {
                Text(text = stringResource(R.string.pagina_1))
            },
            onClick = {
                expanded.value = false
            }
        )

        Divider()

        DropdownMenuItem(
            text = {
                Text(text = stringResource(R.string.pagina_2))
            },
            onClick = {
                onNavigatePagina2()
                expanded.value = false
            }
        )
    }
}

Here is the code of the NavHost

@Composable
fun PresentTest(
    navController: NavHostController = rememberNavController()
) {
    val backStackEntry by navController.currentBackStackEntryAsState()
    val currentScreen = Pagina.valueOf(
        backStackEntry?.destination?.route ?: Pagina.Pagina1.name
    )
    Scaffold(
        topBar = {
            PresentTestAppBar(
                currentScreen = currentScreen
            )
        }
    ) { innerPadding ->
        NavHost(
            navController = navController,
            startDestination = Pagina.Pagina1.name,
            modifier = Modifier.padding(innerPadding)
        ) {
            composable(route = Pagina.Pagina1.name) {
                Pagina1Screen(
                    onNavigatePagina2 = {
                        navController.navigate(Pagina.Pagina2.name)
                    }
                )
            }
            composable(route = Pagina.Pagina2.name) {
                Pagina2Screen(
                    onNavigatePagina1 = {
                        navController.navigate(Pagina.Pagina1.name)
                    }
                )
            }
        }
    }
}

Solution

  • In your DropdownMenuItem, the onNavigatePagina2() function is not defined.

    In your NavHost, you are passing the onNavigatePagina2() function to the Pagina1Screen. So in the Pagina1Screen Composable, you would be able to call the function. But you are not passing it to the TopAppBarDropdownMenu Composable, so you can't call it there.

    You can pass the function to your TopAppBarDropdownMenu to make it available there.
    First, change your PresentTest Composable as follows:

    //...
    Scaffold(
        topBar = {
            PresentTestAppBar(
                currentScreen = currentScreen,
                onNavigatePagina2 = {
                    navController.navigate(Pagina.Pagina2.name)
                }
            )
        }
    ) {
        //...
    }
    

    Then update the PresentTestAppBar Composable as follows:

    @Composable
    PresentTestAppBar(currentScreen: Pagina, onNavigatePagina2: () -> Unit) {
        //...
        actions = { TopAppBarDropdownMenu(onNavigatePagina2) }
        //...
    }
    

    Finally, modify your TopAppBarDropdownMenu Composable, and then your code should work:

    @Composable
    fun TopAppBarDropdownMenu(onNavigatePagina2: () -> Unit) {
       
        //... now, you can call the onNavigatePagina2() function here
    
    }