Home > Software engineering >  How to change the content inside a Scaffold that exists inside drawer in Jetpack Compose?
How to change the content inside a Scaffold that exists inside drawer in Jetpack Compose?

Time:08-04

I have this drawer:

val drawerState = rememberDrawerState(DrawerValue.Closed)
val scope = rememberCoroutineScope()
val items = listOf(Icons.Default.Favorite, Icons.Default.Face, Icons.Default.Email)
val selectedItem = remember { mutableStateOf(items[0]) }

ModalNavigationDrawer(
    drawerState = drawerState,
    drawerContent = {
        items.forEach { item ->
            NavigationDrawerItem(
                icon = { Icon(item, contentDescription = null) },
                label = { Text(item.name) },
                selected = item == selectedItem.value,
                onClick = {
                    scope.launch { drawerState.close() }
                    selectedItem.value = item
                    //How to change the content of Scaffold's content section?
                },
                modifier = Modifier.padding(NavigationDrawerItemDefaults.ItemPadding)
            )
        }
    },
    content = {
        Scaffold(
            topBar = {
                //
            },
            content = { padding ->
                Text(
                    modifier = Modifier.padding(padding),
                    text = "Favorites"
                )
            }
        )
    }
)

Now, when I run the app, I get the correct TopBar and right under it a Text that holds the value of "Favorites". The problem is that I always want to have the same TopBar, and only change the Scaffold's content. So instead of "Favorites" I want to display "Face", when the second item is clicked.

I though to create some composable functions, to display the data, but I cannot call them from inside the onClick. Android Studio is complaining with:

@Composable invocations can only happen from the context of a @Composable function

I also thought on creating states and load that data according to that state. But isn't it so complicated to only display a single text?

In also thought on navigating to other screens but this means that each screen should have it own TopBar, which in my opinion requires adding more complexity to the app for no reason. I'm completely lost. How to solve this issue?

CodePudding user response:

You should just simply update a viewmodel state value in onclick and listen to that value inside your composable. When the value changes you can simply call other composable. It isn't that complex.

CodePudding user response:

Creating a State to change content is not that complicated same goes for puting a NavHost composable inside your content block.

object Routes {
    const val Favorites = "Favorites"
    const val Faces = "Faces"
}

var route by remember {mutableStateOf(Routes.Favorites)}

ModalNavigationDrawer(
    drawerState = drawerState,
    drawerContent = {
        items.forEach { item ->
            NavigationDrawerItem(
                icon = { Icon(item, contentDescription = null) },
                label = { Text(item.name) },
                selected = item == selectedItem.value,
                onClick = {
                    scope.launch { drawerState.close() }
                    selectedItem.value = item
                    // Change route
                    route = some new route...
                },
                modifier = Modifier.padding(NavigationDrawerItemDefaults.ItemPadding)
            )
        }
    },
    content = {
        Scaffold(
            topBar = {
                //
            },
            content = { padding ->
               if(route == Routes.Favorites) {
                  Text(
                    modifier = Modifier.padding(padding),
                    text = "Favorites"
                )
              }else {
                // other routes
              }
            }
        )
    }
)

With NavHost

    NavHost(
        navController = navController,
        startDestination = Routes.Favorites
    ) {
        composable(Routes.Favorites) {
            Favorites()
        }

        composable(Routes. Face) {
            Faces()
        }
    }
  • Related