0

I have a Bottom Bar, and in this composable function I want to call a function that i've set up in a ViewModel in my Apps Navigation's Nav Graph, but can't think of any way to do this? I've played with some interfaces however I'm not getting anywhere

@Composable
fun BottomNavBar(
    currentRoute: String?,
    navigateToBuild: () -> Unit,
    navigateToSaved: () -> Unit
) {
    Column() {

        Row(modifier = Modifier
            .fillMaxWidth()
            .height(1.dp)
            .background(Color.Gray)) {

        }

        BottomAppBar(
            modifier = Modifier
                .height(72.dp),
            backgroundColor = Color.White
        ) {
            navItems.forEach { item ->

                val selected = currentRoute == item.route

                BottomNavigationItem(
                    icon = {
                        Image(
                            painter = painterResource(
                                id = if (selected) item.selectedIcon else 
                                item.unselectedIcon),
                                contentDescription = item.title
                        )
                    },
                    selected = selected,
                    onClick = {
                        when (item.route) {
                            NavigationItem.Build.route -> {
                                navigateToBuild()
                            }
                            NavigationItem.Saved.route -> {
                                navigateToSaved()
                                // I want to call viewmodel function here
                               }
                           }
                        }
                    )
                }
            }
        }
    }

My Bottom bar is part of the scaffold here, and my viewmodel is inside the AppNavigation composable, so they are both completely separate and I can't think of any way for them to communicate?

Scaffold(
    bottomBar = {
        BottomNavBar(
        currentRoute = currentRoute,
        navigateToBuild = { navController.navigate("build/0") },
        navigateToSaved = { navController.navigate(DashboardScreens.Saved.route) })
      }
    ) { innerPadding ->
        Box(
            modifier = Modifier
                .padding(innerPadding)
                .background(Color.White)
        ) {
            AppNavigation(navHostController = navController)
         }
      }
alfietap
  • 1,585
  • 1
  • 15
  • 38
  • Use a state to call the function in the view model. Pass the state to the `AppNavigation` – Abhimanyu Oct 24 '21 at 16:33
  • I think that Abhimanyu is referring to state-hoisting, which is a best-practice in declarative UI Development. Read [here](https://developer.android.com/codelabs/jetpack-compose-state#8). – Richard Onslow Roper Oct 24 '21 at 19:06

1 Answers1

0

In Compose, the view model lifecycle is bound to the compose navigation route (if there is one) or to Activity / Fragment otherwise, depending on where setContent was called from.

The first viewModel() call creates a view model, all other calls to the same class from any composable function will return the same object to you. So as long as you are inside the same navigation route, you can safely call viewModel() from BottomNavBar:

@Composable
fun BottomNavBar(
    currentRoute: String?,
    navigateToBuild: () -> Unit,
    navigateToSaved: () -> Unit
) {
    val viewModel = viewModel<ViewModelClass>()
}

@Composable
fun AppNavigation(navHostController: NavController) {
    val viewModel = viewModel<ViewModelClass>()
}
Phil Dukhov
  • 67,741
  • 15
  • 184
  • 220
  • So my viewmodel isn't in the same navigation route as my bottom bar. My Bottom bar sits at the top level with the scaffold, where as my viewmodel for a particular screen is further down the hierarchy, inside the AppNavigation. If i create the viewmodel inside the Bottom Bar function, it doesn't seem to get access to any of the state i currently hold inside the viewmodel – alfietap Oct 24 '21 at 17:57
  • @alfietap see [this answer](https://stackoverflow.com/a/64961032/3585796) on how to access parent view model from the navigation route, and [this answer](https://stackoverflow.com/a/69002254/3585796) of how to share life model scope between destinations – Phil Dukhov Oct 24 '21 at 18:04