Navigation bileşeni, Jetpack Compose uygulamaları için destek sağlar. Navigation bileşeninin altyapısından ve özelliklerinden yararlanırken composable'lar arasında gezinebilirsiniz.
Compose için özel olarak oluşturulan en yeni alfa gezinme kitaplığı hakkında bilgi edinmek için Navigation 3 dokümanlarına bakın.
Kurulum
Compose'u desteklemek için uygulama modülünüzün build.gradle
dosyasında aşağıdaki bağımlılığı kullanın:
Groovy
dependencies { def nav_version = "2.9.1" implementation "androidx.navigation:navigation-compose:$nav_version" }
Kotlin
dependencies { val nav_version = "2.9.1" implementation("androidx.navigation:navigation-compose:$nav_version") }
Başlayın
Bir uygulamada gezinme işlevini uygularken gezinme ana makinesi, grafik ve denetleyici uygulayın. Daha fazla bilgi için Gezinmeye genel bakış konusuna bakın.
NavController oluşturma
Oluşturma bölümünde NavController
oluşturma hakkında bilgi edinmek için Gezinme denetleyicisi oluşturma başlıklı makalenin Oluşturma bölümüne bakın.
NavHost oluşturma
Oluşturma bölümünde NavHost
oluşturma hakkında bilgi edinmek için Gezinme grafiğinizi tasarlama başlıklı makalenin Oluşturma bölümüne bakın.
Bir composable'a gitme
Bir Composable'a gitme hakkında bilgi edinmek için mimari belgelerindeki Hedefe gitme bölümüne bakın.
Bağımsız değişkenlerle gezinme
Composable hedefler arasında bağımsız değişkenleri iletme hakkında bilgi edinmek için Gezinme grafiğinizi tasarlama başlıklı makalenin Compose bölümüne bakın.
Navigasyon sırasında karmaşık verileri alma
Gezinirken karmaşık veri nesnelerini iletmemeniz, bunun yerine gezinme işlemleri gerçekleştirirken benzersiz bir tanımlayıcı veya başka bir kimlik biçimi gibi gerekli minimum bilgiyi iletmeniz önemle tavsiye edilir:
// Pass only the user ID when navigating to a new destination as argument
navController.navigate(Profile(id = "user1234"))
Karmaşık nesneler, veri katmanı gibi tek bir doğru kaynağında veri olarak depolanmalıdır. Gezindikten sonra hedefinize ulaştığınızda, iletilen kimliği kullanarak tek doğru kaynakta bulunan gerekli bilgileri yükleyebilirsiniz. Veri katmanına erişmekten sorumlu olan ViewModel
işlevinizdeki bağımsız değişkenleri almak için ViewModel
işlevinin SavedStateHandle
işlevini kullanın:
class UserViewModel(
savedStateHandle: SavedStateHandle,
private val userInfoRepository: UserInfoRepository
) : ViewModel() {
private val profile = savedStateHandle.toRoute<Profile>()
// Fetch the relevant user information from the data layer,
// ie. userInfoRepository, based on the passed userId argument
private val userInfo: Flow<UserInfo> = userInfoRepository.getUserInfo(profile.id)
// …
}
Bu yaklaşım, yapılandırma değişiklikleri sırasında veri kaybını ve söz konusu nesne güncellenirken veya değiştirilirken tutarsızlıkları önlemeye yardımcı olur.
Karmaşık verileri neden bağımsız değişken olarak iletmemeniz gerektiğiyle ilgili daha ayrıntılı açıklama ve desteklenen bağımsız değişken türlerinin listesi için Hedefler arasında veri iletme başlıklı makaleyi inceleyin.
Derin bağlantılar
Navigation Compose, composable()
işlevinin bir parçası olarak da tanımlanabilen derin bağlantıları destekler. deepLinks
parametresi, navDeepLink()
yöntemiyle hızlıca oluşturulabilen NavDeepLink
nesnelerin listesini kabul eder:
@Serializable data class Profile(val id: String)
val uri = "https://www.example.com"
composable<Profile>(
deepLinks = listOf(
navDeepLink<Profile>(basePath = "$uri/profile")
)
) { backStackEntry ->
ProfileScreen(id = backStackEntry.toRoute<Profile>().id)
}
Bu derin bağlantılar, belirli bir URL'yi, işlemi veya MIME türünü bir composable ile ilişkilendirmenize olanak tanır. Varsayılan olarak, bu derin bağlantılar harici uygulamalara gösterilmez. Bu derin bağlantıları harici olarak kullanılabilir hale getirmek için uygulamanızın manifest.xml
dosyasına uygun <intent-filter>
öğelerini eklemeniz gerekir. Yukarıdaki örnekte derin bağlantıyı etkinleştirmek için manifest dosyasının <activity>
öğesinin içine aşağıdakileri eklemeniz gerekir:
<activity …>
<intent-filter>
...
<data android:scheme="https" android:host="www.example.com" />
</intent-filter>
</activity>
Derin bağlantı başka bir uygulama tarafından tetiklendiğinde gezinme, otomatik olarak bu composable'a derin bağlantı oluşturur.
Aynı derin bağlantılar, birleştirilebilir öğeden uygun derin bağlantı ile PendingIntent
oluşturmak için de kullanılabilir:
val id = "exampleId"
val context = LocalContext.current
val deepLinkIntent = Intent(
Intent.ACTION_VIEW,
"https://www.example.com/profile/$id".toUri(),
context,
MyActivity::class.java
)
val deepLinkPendingIntent: PendingIntent? = TaskStackBuilder.create(context).run {
addNextIntentWithParentStack(deepLinkIntent)
getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT)
}
Ardından, uygulamanızı derin bağlantı hedefinde açmak için bu deepLinkPendingIntent
öğesini diğer PendingIntent
öğeleri gibi kullanabilirsiniz.
İç İçe Gezinme
İç içe yerleştirilmiş gezinme grafikleri oluşturma hakkında bilgi için İç içe yerleştirilmiş grafikler başlıklı makaleye bakın.
Alt gezinme çubuğuyla entegrasyon
NavController
öğesini birleştirilebilir hiyerarşinizde daha üst bir düzeyde tanımlayarak gezinme bileşenini alt gezinme bileşeni gibi diğer bileşenlere bağlayabilirsiniz. Bu işlemi yaptığınızda alt çubuktaki simgeleri seçerek gezinebilirsiniz.
BottomNavigation
ve BottomNavigationItem
bileşenlerini kullanmak için Android uygulamanıza androidx.compose.material
bağımlılığını ekleyin.
Groovy
dependencies { implementation "androidx.compose.material:material:1.8.3" } android { buildFeatures { compose true } composeOptions { kotlinCompilerExtensionVersion = "1.5.15" } kotlinOptions { jvmTarget = "1.8" } }
Kotlin
dependencies { implementation("androidx.compose.material:material:1.8.3") } android { buildFeatures { compose = true } composeOptions { kotlinCompilerExtensionVersion = "1.5.15" } kotlinOptions { jvmTarget = "1.8" } }
Alt gezinme çubuğundaki öğeleri gezinme grafiğinizdeki rotalara bağlamak için, burada gösterildiği gibi TopLevelRoute
sınıfı ve simgesi olan bir sınıf tanımlamanız önerilir.
data class TopLevelRoute<T : Any>(val name: String, val route: T, val icon: ImageVector)
Ardından, bu rotaları BottomNavigationItem
tarafından kullanılabilecek bir listeye yerleştirin:
val topLevelRoutes = listOf(
TopLevelRoute("Profile", Profile, Icons.Profile),
TopLevelRoute("Friends", Friends, Icons.Friends)
)
BottomNavigation
composable'ınızda currentBackStackEntryAsState()
işlevini kullanarak mevcut NavBackStackEntry
değerini alın. Bu giriş, mevcut NavDestination
'ya erişmenizi sağlar. Her BottomNavigationItem
öğesinin seçili durumu, öğenin rotası ile geçerli hedefin ve üst hedeflerinin rotası karşılaştırılarak belirlenebilir. Bu sayede, NavDestination
hiyerarşisini kullanarak iç içe yerleştirilmiş gezinme kullandığınız durumlarda öğeler işlenebilir.
Öğeye dokunulduğunda ilgili öğeye gidilmesi için öğenin rotası, onClick
lambda'yı navigate
çağrısına bağlamak için de kullanılır. saveState
ve restoreState
işaretlerini kullanarak, alt gezinme öğeleri arasında geçiş yaparken öğenin durumu ve geri yığın doğru şekilde kaydedilir ve geri yüklenir.
val navController = rememberNavController()
Scaffold(
bottomBar = {
BottomNavigation {
val navBackStackEntry by navController.currentBackStackEntryAsState()
val currentDestination = navBackStackEntry?.destination
topLevelRoutes.forEach { topLevelRoute ->
BottomNavigationItem(
icon = { Icon(topLevelRoute.icon, contentDescription = topLevelRoute.name) },
label = { Text(topLevelRoute.name) },
selected = currentDestination?.hierarchy?.any { it.hasRoute(topLevelRoute.route::class) } == true,
onClick = {
navController.navigate(topLevelRoute.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 = Profile, Modifier.padding(innerPadding)) {
composable<Profile> { ProfileScreen(...) }
composable<Friends> { FriendsScreen(...) }
}
}
Burada, NavController.currentBackStackEntryAsState()
yönteminden yararlanarak navController
durumunu NavHost
işlevinden çıkarıp BottomNavigation
bileşeniyle paylaşıyorsunuz. Bu, BottomNavigation
öğesinin otomatik olarak en güncel duruma sahip olduğu anlamına gelir.
Birlikte çalışabilirlik
Gezinme bileşenini Compose ile kullanmak istiyorsanız iki seçeneğiniz vardır:
- Parçalar için Gezinme bileşeniyle bir gezinme grafiği tanımlayın.
- Compose hedeflerini kullanarak Compose'da
NavHost
ile bir gezinme grafiği tanımlayın. Bu yalnızca gezinme grafiğindeki tüm ekranlar composable ise mümkündür.
Bu nedenle, Compose ve View'ları karışık kullanan uygulamalar için Fragment tabanlı gezinme bileşeninin kullanılması önerilir. Daha sonra parçalar, görüntülemeye dayalı ekranları, Compose ekranlarını ve hem görüntülemeleri hem de Compose'u kullanan ekranları tutar. Her bir Fragment'ın içeriği Compose'a aktarıldıktan sonraki adım, bu ekranların tümünü Navigation Compose ile bağlamak ve tüm Fragment'ları kaldırmaktır.
Parçalar için Navigation ile Compose'dan gezinme
Compose kodunun içindeki hedefleri değiştirmek için hiyerarşideki herhangi bir composable'a iletilebilen ve bu composable tarafından tetiklenebilen etkinlikleri kullanıma sunarsınız:
@Composable
fun MyScreen(onNavigate: (Int) -> Unit) {
Button(onClick = { onNavigate(R.id.nav_profile) } { /* ... */ }
}
Parçanızda, NavController
öğesini bulup hedefe giderek Compose ile parçaya dayalı Navigation bileşeni arasında köprü oluşturursunuz:
override fun onCreateView( /* ... */ ) {
setContent {
MyScreen(onNavigate = { dest -> findNavController().navigate(dest) })
}
}
Alternatif olarak, NavController
öğesini Compose hiyerarşinizde aşağıya aktarabilirsiniz.
Ancak basit işlevleri kullanıma sunmak çok daha fazla yeniden kullanılabilir ve test edilebilir.
Test
Her bir composable'ın NavHost
composable'dan ayrı olarak izole bir şekilde test edilmesini sağlamak için gezinme kodunu composable hedeflerinizden ayırın.
Bu nedenle, navController
doğrudan herhangi bir Bu sayede, testlerde navController
örneği gerektirmediğinden tüm composable'larınız ayrı ayrı test edilebilir.
composable
lambda'nın sağladığı dolaylılık düzeyi, gezinme kodunuzu composable'dan ayırmanıza olanak tanır. Bu özellik iki yönde çalışır:
- Yalnızca ayrıştırılmış bağımsız değişkenleri composable işlevinize iletin.
NavController
yerine, gezinmek için composable tarafından tetiklenmesi gereken lambda'ları iletin.
Örneğin, giriş olarak userId
alan ve kullanıcıların bir arkadaşının profil sayfasına gitmesine olanak tanıyan bir ProfileScreen
composable'ın imzası şu şekilde olabilir:
@Composable
fun ProfileScreen(
userId: String,
navigateToFriendProfile: (friendUserId: String) -> Unit
) {
…
}
Bu sayede, ProfileScreen
composable'ı Navigation'dan bağımsız olarak çalışır ve bağımsız olarak test edilebilir. composable
lambda'sı, Navigation API'leri ile composable'ınız arasındaki boşluğu doldurmak için gereken minimum mantığı kapsar:
@Serializable data class Profile(id: String)
composable<Profile> { backStackEntry ->
val profile = backStackEntry.toRoute<Profile>()
ProfileScreen(userId = profile.id) { friendUserId ->
navController.navigate(route = Profile(id = friendUserId))
}
}
NavHost
, composable'larınıza iletilen gezinme işlemleri ve ayrı ekran composable'larınızı test ederek uygulama gezinme şartlarınızı karşılayan testler yazmanız önerilir.
NavHost
test ediliyor
NavHost
test etmeye başlamak için aşağıdaki gezinme testi bağımlılığını ekleyin:
dependencies {
// ...
androidTestImplementation "androidx.navigation:navigation-testing:$navigationVersion"
// ...
}
Uygulamanızın NavHost
öğesini, parametre olarak NavHostController
kabul eden bir composable ile sarmalayın.
@Composable
fun AppNavHost(navController: NavHostController){
NavHost(navController = navController){ ... }
}
Artık gezinme testi yapay nesnesinin bir örneğini TestNavHostController
ileterek AppNavHost
ve NavHost
içinde tanımlanan tüm gezinme mantığını test edebilirsiniz. Uygulamanızın başlangıç hedefini ve NavHost
öğesini doğrulayan bir kullanıcı arayüzü testi şu şekilde görünür:
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()
}
}
Gezinme işlemlerini test etme
Kullanıcı arayüzü öğelerini tıklayarak ve ardından gösterilen hedefi doğrulayarak veya beklenen rotayı mevcut rotayla karşılaştırarak gezinme uygulamanızı birden fazla şekilde test edebilirsiniz.
Uygulamanızın somut uygulamasını test etmek istediğiniz için kullanıcı arayüzündeki tıklamalar tercih edilir. Bunu ayrı ayrı composable işlevlerle birlikte nasıl test edeceğinizi öğrenmek için Jetpack Compose'da Test adlı codelab'e göz atın.
Ayrıca, navController
'nın currentBackStackEntry
özelliğini kullanarak mevcut rotayı beklenen rota ile karşılaştırarak onaylarınızı kontrol etmek için navController
'yı da kullanabilirsiniz:
@Test
fun appNavHost_clickAllProfiles_navigateToProfiles() {
composeTestRule.onNodeWithContentDescription("All Profiles")
.performScrollTo()
.performClick()
assertTrue(navController.currentBackStackEntry?.destination?.hasRoute<Profile>() ?: false)
}
Compose'da test etmenin temelleri hakkında daha fazla bilgi için Compose düzeninizi test etme ve Jetpack Compose'da test etme codelab'ini inceleyin. Gezinme kodunun gelişmiş testi hakkında daha fazla bilgi edinmek için Gezinmeyi Test Etme kılavuzunu ziyaret edin.
Daha fazla bilgi
Jetpack Navigation hakkında daha fazla bilgi edinmek için Navigation bileşenini kullanmaya başlama başlıklı makaleyi inceleyin veya Jetpack Compose Navigation codelab'ini tamamlayın.
Uygulamanızın gezinme özelliğini farklı ekran boyutlarına, yönlerine ve form faktörlerine uyacak şekilde nasıl tasarlayacağınızı öğrenmek için Duyarlı kullanıcı arayüzleri için gezinme başlıklı makaleyi inceleyin.
Modülerleştirilmiş bir uygulamada daha gelişmiş bir Compose gezinme uygulaması hakkında bilgi edinmek için (ör. iç içe grafikler ve alt gezinme çubuğu entegrasyonu gibi kavramlar) GitHub'daki Now in Android uygulamasına göz atın.
Örnekler
Sizin için önerilenler
- Not: JavaScript kapalıyken bağlantı metni gösterilir.
- Compose'da Material Design 2
- Jetpack Navigation'ı Navigation Compose'a taşıma
- Durumu yükseltme