Komponen Navigasi memberikan dukungan untuk aplikasi Jetpack Compose. Anda dapat bernavigasi antar-komponen sekaligus memanfaatkan infrastruktur dan fitur komponen Navigasi.
Penyiapan
Untuk mendukung Compose, gunakan dependensi berikut dalam file build.gradle
modul aplikasi Anda:
Groovy
dependencies { def nav_version = "2.5.3" implementation "androidx.navigation:navigation-compose:$nav_version" }
Kotlin
dependencies { val nav_version = "2.5.3" implementation("androidx.navigation:navigation-compose:$nav_version") }
Memulai
NavController
adalah API pusat untuk komponen Navigasi. API ini bersifat
stateful serta memantau data sebelumnya pada composable yang membentuk
layar di aplikasi Anda dan status setiap layar.
Anda dapat membuat NavController
dengan menggunakan metode rememberNavController()
dalam composable Anda:
val navController = rememberNavController()
Anda harus membuat NavController
di tempat dalam hierarki composable,
yakni tempat semua composable yang perlu mereferensikannya dapat mengaksesnya. Hal ini mengikuti
prinsip pengangkatan status
dan memungkinkan Anda menggunakan NavController
dan status yang diberikannya melalui
currentBackStackEntryAsState()
untuk digunakan sebagai sumber tepercaya demi
mengupdate composable di luar layar. Lihat
Integrasi dengan navbar bawah
untuk contoh fungsi ini.
Membuat NavHost
Setiap NavController
harus
dikaitkan dengan satu composable
NavHost
. NavHost
menautkan NavController
dengan grafik navigasi yang menentukan
beberapa tujuan composable yang seharusnya dapat Anda jelajahi
di antaranya. Saat Anda menavigasi antar-composable, konten NavHost
akan otomatis
direkomposisi.
Setiap tujuan composable dalam grafik navigasi dikaitkan dengan
rute.
Membuat NavHost
memerlukan NavController
yang telah dibuat sebelumnya melalui
rememberNavController()
dan rute tujuan awal grafik Anda.
Pembuatan NavHost
menggunakan sintaksis lambda dari Navigation Kotlin
DSL untuk membuat
grafik navigasi Anda. Anda dapat menambahkan ke struktur navigasi dengan menggunakan metode
composable()
. Metode ini mengharuskan Anda memberikan rute dan
composable yang harus ditautkan ke tujuan:
NavHost(navController = navController, startDestination = "profile") {
composable("profile") { Profile(/*...*/) }
composable("friendslist") { FriendsList(/*...*/) }
/*...*/
}
Menavigasi ke composable
Untuk menavigasi ke tujuan composable di grafik navigasi, Anda harus menggunakan
metode
navigate
. navigate
menggunakan parameter String
tunggal yang mewakili
rute tujuan. Untuk menavigasi dari composable dalam grafik navigasi,
panggil navigate
:
navController.navigate("friendslist")
Secara default,
navigate
menambahkan tujuan baru Anda ke data sebelumnya. Anda dapat
mengubah perilaku navigate
dengan melampirkan opsi navigasi tambahan ke
panggilan navigate()
kami:
// Pop everything up to the "home" destination off the back stack before
// navigating to the "friendslist" destination
navController.navigate("friendslist") {
popUpTo("home")
}
// Pop everything up to and including the "home" destination off
// the back stack before navigating to the "friendslist" destination
navController.navigate("friendslist") {
popUpTo("home") { inclusive = true }
}
// Navigate to the "search” destination only if we’re not already on
// the "search" destination, avoiding multiple copies on the top of the
// back stack
navController.navigate("search") {
launchSingleTop = true
}
Lihat panduan popUpTo untuk kasus penggunaan lainnya.
Menavigasi panggilan yang dipicu oleh fungsi composable lainnya
Fungsi navigate
NavController
mengubah status internal
NavController
. Untuk mematuhi prinsip satu sumber
tepercaya sebanyak mungkin, hanya
fungsi composable atau holder status yang mengangkat instance NavController
dan fungsi composable tersebut yang menggunakan parameter NavController
yang harus melakukan panggilan navigasi. Peristiwa navigasi yang dipicu dari
fungsi composable lainnya yang lebih rendah dalam hierarki UI harus mengekspos peristiwa tersebut
ke pemanggil dengan benar menggunakan fungsi.
Contoh berikut menunjukkan fungsi composable MyAppNavHost
sebagai satu
sumber tepercaya untuk instance NavController
. ProfileScreen
menampilkan
peristiwa sebagai fungsi yang dipanggil saat pengguna mengetuk tombol.
MyAppNavHost
, yang memiliki navigasi ke berbagai layar di aplikasi,
membuat panggilan navigasi ke tujuan yang tepat saat memanggil ProfileScreen
.
@Composable
fun MyAppNavHost(
modifier: Modifier = Modifier,
navController: NavHostController = rememberNavController(),
startDestination: String = "profile"
) {
NavHost(
modifier = modifier,
navController = navController,
startDestination = startDestination
) {
composable("profile") {
ProfileScreen(
onNavigateToFriends = { navController.navigate("friendsList") },
/*...*/
)
}
composable("friendslist") { FriendsListScreen(/*...*/) }
}
}
@Composable
fun ProfileScreen(
onNavigateToFriends: () -> Unit,
/*...*/
) {
/*...*/
Button(onClick = onNavigateToFriends) {
Text(text = "See friends list")
}
}
Anda hanya boleh memanggil navigate()
sebagai bagian dari callback, bukan
bagian dari composable itu sendiri, untuk mencegah pemanggilan navigate()
pada setiap rekomposisi.
Praktik terbaik
Mengekspos peristiwa dari fungsi composable ke pemanggil yang mengetahui cara menangani logika tertentu dalam aplikasi adalah praktik yang baik di Compose saat mengangkat status.
Meskipun mengekspos peristiwa sebagai parameter lambda individual dapat membebani tanda tangan fungsi, hal ini memaksimalkan visibilitas mengenai tanggung jawab fungsi composable. Anda dapat melihat fungsinya secara sekilas.
Alternatif lain yang dapat mengurangi jumlah parameter dalam deklarasi fungsi
mungkin awalnya lebih mudah untuk ditulis, tetapi menyembunyikan beberapa
kelemahan dalam jangka panjang. Misalnya, membuat class wrapper seperti
ProfileScreenEvents
yang memusatkan semua peristiwa di satu tempat. Tindakan ini
akan mengurangi visibilitas fungsi composable saat memeriksa
definisi fungsinya. Hal ini akan menambahkan class dan metode lain ke jumlah project.
Selain itu, Anda perlu membuat dan mengingat instance class tersebut setiap kali Anda memanggil
fungsi composable tersebut. Selain itu, untuk menggunakan kembali class wrapper tersebut sebanyak mungkin,
pola ini mendorong penerusan instance class tersebut ke bagian bawah hierarki UI,
bukan praktik terbaik untuk meneruskan ke composable hanya yang
dibutuhkan.
Menavigasi dengan argumen
Navigation Compose juga mendukung penerusan argumen di antara tujuan composable. Untuk melakukannya, Anda perlu menambahkan placeholder argumen ke rute, mirip dengan cara Anda menambahkan argumen ke deep link saat menggunakan library navigasi dasar:
NavHost(startDestination = "profile/{userId}") {
...
composable("profile/{userId}") {...}
}
Secara default, semua argumen diuraikan sebagai string. Parameter arguments
dari
composable()
menerima daftar NamedNavArgument
. Anda dapat dengan cepat
membuat NamedNavArgument
menggunakan metode navArgument
, lalu menentukan
type
persisnya:
NavHost(startDestination = "profile/{userId}") {
...
composable(
"profile/{userId}",
arguments = listOf(navArgument("userId") { type = NavType.StringType })
) {...}
}
Anda harus mengekstrak argumen dari NavBackStackEntry
yang
tersedia di lambda fungsi composable()
.
composable("profile/{userId}") { backStackEntry ->
Profile(navController, backStackEntry.arguments?.getString("userId"))
}
Untuk meneruskan argumen ke tujuan, Anda perlu menambahkannya ke rute
saat melakukan panggilan navigate
:
navController.navigate("profile/user1234")
Untuk daftar jenis yang didukung, lihat Meneruskan data di antara tujuan.
Mengambil data kompleks saat menavigasi
Sangat disarankan untuk tidak meneruskan objek data yang kompleks saat menavigasi, tetapi sebagai gantinya teruskan informasi minimum yang diperlukan, seperti ID unik atau bentuk ID lainnya, sebagai argumen saat melakukan tindakan navigasi:
// Pass only the user ID when navigating to a new destination as argument
navController.navigate("profile/user1234")
Objek yang kompleks harus disimpan sebagai data dalam satu sumber tepercaya, seperti
lapisan data. Begitu Anda tiba di tujuan setelah menavigasi, Anda dapat
memuat informasi yang diperlukan dari satu sumber tepercaya dengan menggunakan
ID yang diteruskan. Untuk mengambil argumen di ViewModel yang bertanggung jawab
mengakses lapisan data, Anda dapat menggunakan SavedStateHandle
ViewModel’s
:
class UserViewModel(
savedStateHandle: SavedStateHandle,
private val userInfoRepository: UserInfoRepository
) : ViewModel() {
private val userId: String = checkNotNull(savedStateHandle["userId"])
// Fetch the relevant user information from the data layer,
// ie. userInfoRepository, based on the passed userId argument
private val userInfo: Flow<UserInfo> = userInfoRepository.getUserInfo(userId)
// …
}
Pendekatan ini membantu mencegah kehilangan data selama perubahan konfigurasi dan inkonsistensi saat objek yang dimaksud sedang diperbarui atau berubah.
Untuk penjelasan yang lebih mendalam tentang alasan Anda harus menghindari penerusan data kompleks sebagai argumen, serta daftar jenis argumen yang didukung, lihat Meneruskan data antar-tujuan.
Menambahkan argumen opsional
Navigation Compose juga mendukung argumen navigasi opsional. Argumen opsional memiliki dua perbedaan dengan argumen yang diwajibkan:
- Argumen ini harus disertakan menggunakan sintaksis parameter kueri (
"?argName={argName}"
) - Argumen harus memiliki
defaultValue
yang ditetapkan, ataunullability = true
(yang secara implisit menetapkan nilai default kenull
)
Ini berarti bahwa semua argumen opsional harus ditambahkan secara eksplisit ke fungsi
composable()
sebagai daftar:
composable(
"profile?userId={userId}",
arguments = listOf(navArgument("userId") { defaultValue = "user1234" })
) { backStackEntry ->
Profile(navController, backStackEntry.arguments?.getString("userId"))
}
Sekarang, meskipun tidak ada argumen yang diteruskan ke tujuan, defaultValue
"user1234" akan digunakan sebagai gantinya.
Struktur penanganan argumen melalui rute berarti bahwa composable Anda tetap sepenuhnya independen dari Navigasi dan membuatnya jauh lebih mudah diuji.
Deep link
Navigation Compose mendukung deep link implisit yang juga dapat ditentukan sebagai bagian dari
fungsi composable()
. Parameter deepLinks
menerima daftar
NavDeepLink
yang dapat dibuat dengan cepat menggunakan
metode navDeepLink
:
val uri = "https://www.example.com"
composable(
"profile?id={id}",
deepLinks = listOf(navDeepLink { uriPattern = "$uri/{id}" })
) { backStackEntry ->
Profile(navController, backStackEntry.arguments?.getString("id"))
}
Deep link ini memungkinkan Anda mengatribusikan URL, tindakan, atau jenis mime tertentu dengan
composable. Secara default, deep link ini tidak diekspos ke aplikasi eksternal. Untuk
membuat deep link ini tersedia secara eksternal, Anda harus menambahkan elemen
<intent-filter>
yang sesuai ke file manifest.xml
aplikasi. Untuk mengaktifkan
deep link di atas, Anda harus menambahkan yang berikut di dalam elemen <activity>
dari manifes:
<activity …>
<intent-filter>
...
<data android:scheme="https" android:host="www.example.com" />
</intent-filter>
</activity>
Navigasi otomatis membuat deep link ke dalam composable tersebut saat deep link dipicu oleh aplikasi lain.
Deep link yang sama ini juga dapat digunakan untuk mem-build PendingIntent
dengan
deep link yang sesuai dari composable:
val id = "exampleId"
val context = LocalContext.current
val deepLinkIntent = Intent(
Intent.ACTION_VIEW,
"https://www.example.com/$id".toUri(),
context,
MyActivity::class.java
)
val deepLinkPendingIntent: PendingIntent? = TaskStackBuilder.create(context).run {
addNextIntentWithParentStack(deepLinkIntent)
getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT)
}
Anda selanjutnya dapat menggunakan deepLinkPendingIntent
ini seperti PendingIntent
lainnya untuk
membuka aplikasi di tujuan deep link.
Navigasi Bertingkat
Tujuan dapat dikelompokkan ke dalam grafik bertingkat untuk memodulasi alur tertentu di UI aplikasi. Contohnya adalah alur login mandiri.
Grafik bertingkat mengenkapsulasi tujuannya. Seperti pada grafik root, grafik bertingkat harus memiliki tujuan yang diidentifikasi sebagai tujuan awal menurut rutenya. Ini adalah tujuan yang dituju saat Anda menavigasi ke rute yang terkait dengan grafik bertingkat.
Untuk menambahkan grafik bertingkat ke NavHost
, Anda dapat menggunakan fungsi
ekstensi navigation
:
NavHost(navController, startDestination = "home") {
...
// Navigating to the graph via its route ('login') automatically
// navigates to the graph's start destination - 'username'
// therefore encapsulating the graph's internal routing logic
navigation(startDestination = "username", route = "login") {
composable("username") { ... }
composable("password") { ... }
composable("registration") { ... }
}
...
}
Sebaiknya Anda membagi grafik navigasi menjadi beberapa metode seiring bertambahnya ukuran grafik. Ini juga memungkinkan beberapa modul memberi kontribusi grafik navigasinya sendiri.
fun NavGraphBuilder.loginGraph(navController: NavController) {
navigation(startDestination = "username", route = "login") {
composable("username") { ... }
composable("password") { ... }
composable("registration") { ... }
}
}
Dengan membuat metode menjadi metode ekstensi di NavGraphBuilder
, Anda dapat menggunakannya
bersama dengan metode ekstensi navigation
, composable
, dan dialog
yang telah di-build:
NavHost(navController, startDestination = "home") {
...
loginGraph(navController)
...
}
Integrasi dengan menu navigasi bawah
Dengan menentukan NavController
pada level yang lebih tinggi dalam hierarki composable,
Anda dapat menghubungkan Navigasi dengan komponen lain seperti komponen navigasi
bawah. Dengan melakukan hal ini, Anda dapat menavigasi dengan memilih ikon di
panel bawah.
Untuk menggunakan komponen BottomNavigation
dan BottomNavigationItem
,
tambahkan dependensi androidx.compose.material
ke aplikasi Android Anda.
Groovy
dependencies { implementation "androidx.compose.material:material:1.3.1" } android { buildFeatures { compose true } composeOptions { kotlinCompilerExtensionVersion = "1.4.3" } kotlinOptions { jvmTarget = "1.8" } }
Kotlin
dependencies { implementation("androidx.compose.material:material:1.3.1") } android { buildFeatures { compose = true } composeOptions { kotlinCompilerExtensionVersion = "1.4.3" } kotlinOptions { jvmTarget = "1.8" } }
Untuk menautkan item di menu navigasi bawah ke rute di grafik navigasi,
sebaiknya tetapkan class tertutup, seperti Screen
yang terlihat di sini, yang
berisi rute dan ID resource String untuk tujuan.
sealed class Screen(val route: String, @StringRes val resourceId: Int) {
object Profile : Screen("profile", R.string.profile)
object FriendsList : Screen("friendslist", R.string.friends_list)
}
Lalu, tempatkan item tersebut dalam daftar yang dapat digunakan oleh
BottomNavigationItem
:
val items = listOf(
Screen.Profile,
Screen.FriendsList,
)
Pada composable BottomNavigation
, dapatkan NavBackStackEntry
saat ini
menggunakan fungsi currentBackStackEntryAsState()
. Entri ini memberi Anda
akses ke NavDestination
saat ini. Status yang dipilih dari setiap
BottomNavigationItem
selanjutnya dapat ditentukan dengan membandingkan rute item
dengan rute tujuan saat ini dan tujuan induknya
(untuk menangani kasus saat Anda menggunakan navigasi bertingkat) melalui
hierarki NavDestination
.
Rute item juga digunakan untuk menghubungkan lambda onClick
ke panggilan ke
navigate
agar mengetuk item akan membuka item tersebut. Dengan menggunakan
tanda saveState
dan restoreState
, status dan data sebelumnya dari item tersebut
disimpan dan dipulihkan dengan benar saat Anda beralih di antara item navigasi
bawah.
val navController = rememberNavController()
Scaffold(
bottomBar = {
BottomNavigation {
val navBackStackEntry by navController.currentBackStackEntryAsState()
val currentDestination = navBackStackEntry?.destination
items.forEach { screen ->
BottomNavigationItem(
icon = { Icon(Icons.Filled.Favorite, contentDescription = null) },
label = { Text(stringResource(screen.resourceId)) },
selected = currentDestination?.hierarchy?.any { it.route == screen.route } == true,
onClick = {
navController.navigate(screen.route) {
// Pop up to the start destination of the graph to
// avoid building up a large stack of destinations
// on the back stack as users select items
popUpTo(navController.graph.findStartDestination().id) {
saveState = true
}
// Avoid multiple copies of the same destination when
// reselecting the same item
launchSingleTop = true
// Restore state when reselecting a previously selected item
restoreState = true
}
}
)
}
}
}
) { innerPadding ->
NavHost(navController, startDestination = Screen.Profile.route, Modifier.padding(innerPadding)) {
composable(Screen.Profile.route) { Profile(navController) }
composable(Screen.FriendsList.route) { FriendsList(navController) }
}
}
Di sini, Anda memanfaatkan metode NavController.currentBackStackEntryAsState()
untuk
mengangkat status navController
dari fungsi NavHost
, dan
membagikannya ke komponen BottomNavigation
. Ini berarti
BottomNavigation
otomatis memiliki status terbaru.
Keamanan jenis di Navigation Compose
Kode pada halaman ini tidak aman dari error jenis. Anda dapat memanggil fungsi navigate()
dengan rute yang tidak ada atau argumen yang salah. Namun, Anda dapat
membuat struktur kode Navigasi agar aman dari error jenis saat runtime. Dengan begitu, Anda dapat
menghindari error dan memastikan bahwa:
- Argumen yang Anda berikan saat membuka grafik navigasi atau tujuan merupakan jenis yang tepat dan semua argumen yang diperlukan ada.
- Argumen yang Anda ambil dari
SavedStateHandle
adalah jenis argumen yang tepat.
Untuk informasi selengkapnya tentang hal ini, lihat Dokumentasi keamanan jenis Navigasi.
Interoperabilitas
Jika ingin menggunakan komponen Navigasi dengan Compose, Anda memiliki dua opsi:
- Menentukan grafik navigasi dengan komponen Navigasi untuk fragmen.
- Menentukan grafik navigasi dengan
NavHost
di Compose menggunakan tujuan Compose. Hal ini hanya dapat dilakukan jika semua layar di grafik navigasi berupa composable.
Oleh karena itu, rekomendasi untuk aplikasi Compose dan View campuran adalah menggunakan komponen Navigasi berbasis Fragment. Fragment kemudian akan menyimpan layar berbasis View, layar Compose, dan layar yang menggunakan View dan Compose. Setelah setiap konten Fragment berada di Compose, langkah berikutnya adalah mengikat semua layar tersebut dengan Navigation Compose dan menghapus semua Fragment.
Menavigasi dari Compose dengan Navigasi untuk fragmen
Untuk mengubah tujuan di dalam kode Compose, Anda menampilkan peristiwa yang dapat diteruskan ke dan dipicu oleh setiap komponen dalam hierarki:
@Composable
fun MyScreen(onNavigate: (Int) -> ()) {
Button(onClick = { onNavigate(R.id.nav_profile) } { /* ... */ }
}
Dalam fragmen, Anda membuat bridge antara Compose dan komponen Navigasi
berbasis fragmen dengan menemukan NavController
dan menavigasi ke
tujuan:
override fun onCreateView( /* ... */ ) {
setContent {
MyScreen(onNavigate = { dest -> findNavController().navigate(dest) })
}
}
Atau, Anda dapat meneruskan NavController
ke hierarki Compose.
Namun, menampilkan fungsi sederhana jauh lebih dapat digunakan kembali dan dapat diuji.
Pengujian
Sebaiknya Anda memisahkan kode Navigasi dari
tujuan composable untuk memungkinkan pengujian setiap composable secara terpisah
dari composable NavHost
.
Ini berarti Anda tidak boleh meneruskan navController
langsung ke composable mana pun, tetapi
meneruskan callback navigasi sebagai parameter. Hal ini memungkinkan semua composable
Anda dapat diuji satu per satu, karena tidak memerlukan instance
navController
dalam pengujian.
Level pengalihan tidak langsung yang disediakan oleh lambda composable
memungkinkan Anda
memisahkan kode Navigasi dari composable itu sendiri. Hal ini bekerja dalam
dua arah:
- Hanya meneruskan argumen yang diuraikan ke dalam komponen
- Meneruskan lambda yang seharusnya dipicu oleh composable untuk menavigasi,
bukan
NavController
itu sendiri.
Misalnya, composable Profile
yang mengambil userId
sebagai input dan memungkinkan
pengguna menavigasi ke halaman profil teman mungkin memiliki tanda tangan:
@Composable
fun Profile(
userId: String,
navigateToFriendProfile: (friendUserId: String) -> Unit
) {
…
}
Dengan cara ini, composable Profile
berfungsi secara independen dari Navigasi,
sehingga membuatnya dapat diuji secara terpisah. Lambda composable
akan
mengenkapsulasi logika minimal yang diperlukan untuk menjembatani kesenjangan antara Navigation
API dan composable Anda:
composable(
"profile?userId={userId}",
arguments = listOf(navArgument("userId") { defaultValue = "user1234" })
) { backStackEntry ->
Profile(backStackEntry.arguments?.getString("userId")) { friendUserId ->
navController.navigate("profile?userId=$friendUserId")
}
}
Sebaiknya tulis pengujian yang mencakup persyaratan navigasi aplikasi Anda
dengan menguji NavHost
, tindakan navigasi yang diteruskan
ke composable serta setiap composable layar.
Menguji NavHost
Untuk mulai menguji NavHost
, tambahkan dependensi pengujian navigasi berikut:
dependencies {
// ...
androidTestImplementation "androidx.navigation:navigation-testing:$navigationVersion"
// ...
}
Anda dapat menyiapkan subjek pengujian NavHost
dan meneruskan
sebuah instance dari instance navController
ke subjek pengujian tersebut. Untuk melakukannya, artefak
pengujian Navigasi menyediakan TestNavHostController
. Pengujian UI yang
memverifikasi tujuan awal aplikasi Anda dan NavHost
akan terlihat seperti ini:
class NavigationTest {
@get:Rule
val composeTestRule = createComposeRule()
lateinit var navController: TestNavHostController
@Before
fun setupAppNavHost() {
composeTestRule.setContent {
navController = TestNavHostController(LocalContext.current)
navController.navigatorProvider.addNavigator(ComposeNavigator())
AppNavHost(navController = navController)
}
}
// Unit test
@Test
fun appNavHost_verifyStartDestination() {
composeTestRule
.onNodeWithContentDescription("Start Screen")
.assertIsDisplayed()
}
}
Menguji tindakan navigasi
Anda dapat menguji implementasi navigasi dalam beberapa cara dengan melakukan klik pada elemen UI, lalu memverifikasi tujuan yang ditampilkan atau dengan membandingkan rute yang diharapkan dengan rute saat ini.
Karena Anda ingin menguji penerapan aplikasi konkret, sebaiknya klik UI. Untuk mempelajari cara mengujinya beserta setiap fungsi composable individualnya, pastikan Anda melihat codelab Pengujian di Jetpack Compose.
Anda juga dapat menggunakan navController
untuk memeriksa pernyataan dengan
membandingkan rute String saat ini dengan yang diharapkan, menggunakan
currentBackStackEntry
navController
:
@Test
fun appNavHost_clickAllProfiles_navigateToProfiles() {
composeTestRule.onNodeWithContentDescription("All Profiles")
.performScrollTo()
.performClick()
val route = navController.currentBackStackEntry?.destination?.route
assertEquals(route, "profiles")
}
Untuk panduan selengkapnya tentang dasar-dasar pengujian Compose, buka dokumen Pengujian Compose dan codelab Pengujian di Jetpack Compose. Untuk mempelajari lebih lanjut pengujian lanjutan kode navigasi, kunjungi panduan Navigasi Pengujian.
Mempelajari lebih lanjut
Untuk mempelajari Navigasi Jetpack lebih lanjut, lihat Mulai menggunakan komponen Navigasi atau baca codelab Navigasi Jetpack Compose.
Untuk mempelajari cara mendesain navigasi aplikasi agar dapat beradaptasi dengan berbagai ukuran, orientasi, dan faktor bentuk layar, lihat Navigasi untuk UI responsif.
Untuk mempelajari implementasi Navigation Compose lanjutan di aplikasi modular, termasuk konsep seperti grafik bertingkat dan integrasi menu navigasi bawah, lihat repositori Now in Android.