Skip to Content

Navigation trong Jetpack Compose

1. Setup

Dependencies

implementation("androidx.navigation:navigation-compose:2.7.7")

2. NavController và NavHost

@Composable fun MyApp() { val navController = rememberNavController() NavHost( navController = navController, startDestination = "home" ) { composable("home") { HomeScreen( onNavigateToDetail = { id -> navController.navigate("detail/$id") } ) } composable("detail/{id}") { backStackEntry -> val id = backStackEntry.arguments?.getString("id") DetailScreen(id = id) } } }

3. Navigate với Arguments

Path Arguments

NavHost(...) { composable("detail/{userId}") { backStackEntry -> val userId = backStackEntry.arguments?.getString("userId") DetailScreen(userId) } } // Navigate navController.navigate("detail/123")

Type-safe Arguments

composable( route = "detail/{id}", arguments = listOf( navArgument("id") { type = NavType.IntType } ) ) { backStackEntry -> val id = backStackEntry.arguments?.getInt("id") ?: 0 DetailScreen(id) }

Optional Arguments

composable( route = "search?query={query}", arguments = listOf( navArgument("query") { type = NavType.StringType defaultValue = "" nullable = true } ) ) { backStackEntry -> val query = backStackEntry.arguments?.getString("query") SearchScreen(query) } // Navigate navController.navigate("search?query=kotlin")

4. Navigation Back Stack

// Navigate và pop tất cả đến destination navController.navigate("home") { popUpTo("home") { inclusive = true } } // Navigate và clear back stack navController.navigate("login") { popUpTo(0) { inclusive = true } } // Pop back navController.popBackStack() // Navigate up (respect parent) navController.navigateUp()

5. Bottom Navigation

@Composable fun MainScreen() { val navController = rememberNavController() Scaffold( bottomBar = { NavigationBar { val navBackStackEntry by navController.currentBackStackEntryAsState() val currentRoute = navBackStackEntry?.destination?.route listOf( BottomNavItem("home", "Home", Icons.Default.Home), BottomNavItem("search", "Search", Icons.Default.Search), BottomNavItem("profile", "Profile", Icons.Default.Person) ).forEach { item -> NavigationBarItem( icon = { Icon(item.icon, item.label) }, label = { Text(item.label) }, selected = currentRoute == item.route, onClick = { navController.navigate(item.route) { popUpTo(navController.graph.startDestinationId) { saveState = true } launchSingleTop = true restoreState = true } } ) } } } ) { padding -> NavHost( navController, startDestination = "home", modifier = Modifier.padding(padding) ) { composable("home") { HomeScreen() } composable("search") { SearchScreen() } composable("profile") { ProfileScreen() } } } }

6. Nested Navigation

NavHost(navController, startDestination = "main") { // Main graph navigation(startDestination = "home", route = "main") { composable("home") { HomeScreen() } composable("detail/{id}") { DetailScreen() } } // Auth graph navigation(startDestination = "login", route = "auth") { composable("login") { LoginScreen() } composable("register") { RegisterScreen() } } }
composable( route = "detail/{id}", deepLinks = listOf( navDeepLink { uriPattern = "myapp://detail/{id}" }, navDeepLink { uriPattern = "https://myapp.com/detail/{id}" } ) ) { backStackEntry -> DetailScreen(backStackEntry.arguments?.getString("id")) }

8. Passing Data Back

// Screen A: Set result listener val result = navController.currentBackStackEntry ?.savedStateHandle ?.getLiveData<String>("key") // Screen B: Return result navController.previousBackStackEntry ?.savedStateHandle ?.set("key", "result value") navController.popBackStack()

9. Animation

composable( route = "detail", enterTransition = { slideInHorizontally(initialOffsetX = { 1000 }) }, exitTransition = { slideOutHorizontally(targetOffsetX = { -1000 }) }, popEnterTransition = { slideInHorizontally(initialOffsetX = { -1000 }) }, popExitTransition = { slideOutHorizontally(targetOffsetX = { 1000 }) } ) { DetailScreen() }

10. Type-Safe Navigation (Kotlin Serialization)

@Serializable data class Detail(val id: Int) @Serializable object Home NavHost(navController, startDestination = Home) { composable<Home> { HomeScreen() } composable<Detail> { backStackEntry -> val detail: Detail = backStackEntry.toRoute() DetailScreen(detail.id) } } // Navigate navController.navigate(Detail(id = 123))

📝 Tóm tắt

ConceptMô tả
NavControllerĐiều khiển navigation
NavHostContainer cho destinations
composableĐịnh nghĩa destination
navArgumentTruyền arguments
popUpToPop back stack
Deep LinksExternal URLs
Nested NavigationGraphs lồng nhau
Last updated on