Search code examples
androidandroid-jetpack-composenavigation-compose

do I have to pass the navController to all my composables?


I am new to jetpack Composable. I'm trying to build a new app using Composables in MainActivity. so there will be only one activity and no fragments and all Composables. I want to know do I have to pass the navController to all the Composables as parameter so inside the function,I can jump to other composables. cause I dont find a way to obtain the controller inside my composable function. hope you can help me. thanks a lot

MyApp.kt  without a class
@Composable
fun MyApp() {
    val navController = rememberNavController()
    NavHost(navController = navController, startDestination = "home_page") {
        composable("home_page") {
            HomePage(HomePageData())
        }
        composable("login_page") {
            LoginPage(navController)
        }

    }
}
HomePage.kt without a class
@Composable
fun HomePage(viewModel: HomePageData) {
    Surface {
          //val navController = rememberNavController()
          //with this remeberNavController(). I got  another object other than the one in MyApp(). using this controller, some nullPointExpception throwed.
        Text(viewModel.pageText, Modifier.clickable {
           //I want to navigate to LoginPage upon this click.
        })
    }
}

here's my code. My problem is that I dont know how to do the jump in the click scope .


Solution

  • Jetpack Compose is mostly a single-activity application so you can manage navigation between the screens.

    Here is the solution. The NavController is the central API for the Navigation component. It is stateful and keeps track of the back stack of composables that make up the screens in your app and the state of each screen

    For better Routing and to avoid any typo errors we are using Sealed Class.

    Step 1 : Screens.kt

    sealed class Screens(val route : String) {
            object Login : Screens("login")
            object Home : Screens("home")    
    }
    

    Once You define your routing. now it's time to define the NavHost which works as a screen container where you can switch between screens suing NavController. Let's see how It works.

    Step 2 : In you MainActivity make a composable which will holds NavHost.

    @Composable
    fun NestedNavigationExample() {
        val navController = rememberNavController()
        NavHost(
            navController = navController,
            startDestination = Screens.Home.route
        ) {
                composable(route = Screens.Home.route) {
                    HomeScreen {
                        navController.navigate(it)
                    }
                }
                composable(route = Screens.Login.route) {
                    LoginScreen {
                        navController.navigate(it)
                    }
                }
        }
    }
    

    Here, we have taken navController which will manage screen transitions. NavHost needs a starting or initial screen so we have given Home as a starting screen.

    Step 3 : Define your screens

    HomeScreen

    @OptIn(ExperimentalMaterial3Api::class)
    @Composable
    fun HomeScreen(navigateTo: (route: String) -> Unit) {
        Scaffold(topBar = {
            TopAppBar(
                title = { Text(text = "Home") },
                colors = TopAppBarDefaults.topAppBarColors(containerColor = MaterialTheme.colorScheme.primary)
            )
        }) {
            Column(
                Modifier
                    .padding(it)
                    .fillMaxSize(),
                horizontalAlignment = Alignment.CenterHorizontally,
                verticalArrangement = Arrangement.Center
            ) {
                Button(onClick = {
                    navigateTo(Screens.Login.route)
                }) {
                    Text(text = "Navigate to Login")
                }
            }
        }
    }
    

    LoginScreen

    @OptIn(ExperimentalMaterial3Api::class)
    @Composable
    fun LoginScreen() {
        Scaffold(topBar = {
            TopAppBar(
                title = { Text(text = "Login") },
                colors = TopAppBarDefaults.topAppBarColors(containerColor = MaterialTheme.colorScheme.primary)
            )
        }) {
            Column(
                Modifier
                    .padding(it)
                    .fillMaxSize(),
                horizontalAlignment = Alignment.CenterHorizontally,
                verticalArrangement = Arrangement.Center
            ) {
                    Text(text = "Login Screen Content")
            }
        }
    }
    

    Note: When you want to navigate to a specific route pass it as a lambda parameter and then navController.navigate(route) will take you to that screen.