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 .
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.