Gezinme bileşeni, Jetpack Compose uygulamaları için destek sağlar. Navigasyon bileşeninin altyapısından ve özelliklerinden yararlanırken composable'lar arasında gezinebilirsiniz.
Kurulum
Compose'u desteklemek için uygulama modülünüzün build.gradle
dosyasında aşağıdaki bağımlılığı kullanın:
Eski
dependencies { def nav_version = "2.8.0" implementation "androidx.navigation:navigation-compose:$nav_version" }
Kotlin
dependencies { val nav_version = "2.8.0" implementation("androidx.navigation:navigation-compose:$nav_version") }
Başlayın
Bir uygulamada gezinme özelliğini uygularken gezinme ana makinesi, grafiği ve denetleyicisi uygulayın. Daha fazla bilgi için Gezinme başlıklı makaleyi inceleyin.
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ştur'da NavHost
oluşturma hakkında bilgi edinmek için Gezinme grafiğinizi tasarlama başlıklı makalenin Oluştur bölümüne bakın.
Bir composable'a git
Bir Composable'a gitme hakkında bilgi edinmek için mimari belgelerindeki Bir hedefe gitme bölümüne bakın.
Bağımsız değişkenlerle gezin
Oluşturulabilir hedefler arasında bağımsız değişkenleri iletme hakkında bilgi için Gezinme grafiğinizi tasarlama başlıklı makalenin Oluşturma bölümüne bakın.
Gezerken karmaşık verileri alma
Gezinirken karmaşık veri nesnelerini aktarmamanız, bunun yerine gezinme işlemlerini gerçekleştirirken bağımsız tanımlayıcı veya başka bir kimlik biçimi gibi gerekli minimum bilgileri 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 kaynakta veri olarak depolanmalıdır. Gezinme işleminden sonra hedefinize ulaştığınızda, iletilen kimliği kullanarak gerekli bilgileri tek doğru kaynaktan yükleyebilirsiniz. ViewModel
içinde veri katmanına erişmekten sorumlu bağımsız değişkenleri almak için ViewModel
öğesinin SavedStateHandle
öğesini 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 ortaya çıkabilecek tutarsızlıkları önlemeye yardımcı olur.
Karmaşık verileri neden bağımsız değişken olarak iletmekten kaçınmanız gerektiğine dair daha ayrıntılı bir açıklama ve desteklenen bağımsız değişken türlerinin listesi için Hedefler arasında veri aktarma başlıklı makaleyi inceleyin.
Derin bağlantılar
Gezinme Oluşturma, composable()
işlevinin bir parçası olarak tanımlanabilen derin bağlantıları da destekler. deepLinks
parametresi, navDeepLink()
yöntemi kullanılarak hızlıca oluşturulabilen NavDeepLink
nesnelerinin bir 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 derlenebilir öğeyle 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. Önceki örnekteki derin bağlantıyı etkinleştirmek için manifest dosyasının <activity>
öğesine 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 ilgili bileşime derin bağlantı oluşturur.
Aynı derin bağlantılar, bir composable'dan uygun derin bağlantıyla 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
değerini diğer tüm PendingIntent
değerleri gibi kullanabilirsiniz.
İç İçe Navigasyon
İç içe yerleştirilmiş gezinme grafikleri oluşturma hakkında bilgi edinmek için İç içe yerleştirilmiş grafikler başlıklı makaleyi inceleyin.
Alt gezinme çubuğuyla entegrasyon
NavController
öğesini, birleştirilebilir hiyerarşinizde daha üst bir seviyede tanımlayarak gezinme menüsünü alt gezinme menüsü gibi diğer bileşenlere bağlayabilirsiniz. Bu sayede, 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.7.5" } android { buildFeatures { compose true } composeOptions { kotlinCompilerExtensionVersion = "1.5.15" } kotlinOptions { jvmTarget = "1.8" } }
Kotlin
dependencies { implementation("androidx.compose.material:material:1.7.5") } 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österilen TopLevelRoute
gibi bir rota 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
bileşeninizde currentBackStackEntryAsState()
işlevini kullanarak mevcut NavBackStackEntry
değerini alın. Bu giriş, mevcut NavDestination
'e erişmenizi sağlar. NavDestination
hiyerarşisini kullanarak iç içe yerleştirilmiş gezinme özelliğini kullandığınızda, her BottomNavigationItem
öğesinin seçili durumu, öğenin yolu mevcut hedefin ve üst hedeflerinin yoluyla karşılaştırılarak belirlenebilir.
Öğenin rotası, onClick
lambda'sını navigate
çağrısına bağlamak için de kullanılır. Böylece öğeye dokunulduğunda ilgili öğeye gidilir. saveState
ve restoreState
işaretçileri kullanılarak, alt gezinme öğeleri arasında geçiş yaptığınızda ilgili öğ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
durumunu NavHost
işlevinden kaldırmak ve BottomNavigation
bileşeniyle paylaşmak için NavController.currentBackStackEntryAsState()
yönteminden yararlanıyorsunuz. Bu, BottomNavigation
'ün otomatik olarak en güncel durumda olduğu anlamına gelir.
Birlikte çalışabilirlik
Gezinme bileşenini Oluştur ile kullanmak istiyorsanız iki seçeneğiniz vardır:
- Gezinme bileşenini kullanarak fragmanlar için bir gezinme grafiği tanımlayın.
- Oluştur hedeflerini kullanarak Oluştur'da
NavHost
içeren bir gezinme grafiği tanımlayın. Bu işlem yalnızca gezinme grafiğindeki tüm ekranlar birleştirilebilirse mümkündür.
Bu nedenle, karma Oluşturma ve Görünümler uygulamaları için önerimiz Parça tabanlı Gezinme bileşenini kullanmaktır. Parçalar; Görüntüleme tabanlı ekranları, Oluşturma ekranlarını ve hem Görünümler hem de Oluştur'u kullanan ekranları tutar. Her bir Fragment'in içeriği Oluştur'a eklendikten sonra, sonraki adım bu ekranların tümünü Gezinme Oluştur ile bağlamak ve tüm Fragment'leri kaldırmaktır.
Compose'dan fragmanlar için gezinme ile gezinme
Oluşturma kodu içindeki hedefleri değiştirmek için hiyerarşide herhangi bir bileşene iletilebilecek ve bileşen tarafından tetiklenebilecek etkinlikleri gösterirsiniz:
@Composable
fun MyScreen(onNavigate: (Int) -> Unit) {
Button(onClick = { onNavigate(R.id.nav_profile) } { /* ... */ }
}
Parçanızda, NavController
öğesini bulup hedefe giderek Oluştur ve parça tabanlı Gezinme bileşeni arasında köprü oluşturursunuz:
override fun onCreateView( /* ... */ ) {
setContent {
MyScreen(onNavigate = { dest -> findNavController().navigate(dest) })
}
}
Alternatif olarak, NavController
öğesini Oluşturma hiyerarşinizden aşağı aktarabilirsiniz.
Ancak basit işlevler çok daha fazla yeniden kullanılabilir ve test edilebilir.
Test
Her bir derlenebilir öğeyi NavHost
derlenebilir öğesinden ayrı olarak tek başına test etmek için gezinme kodunu derlenebilir hedeflerinizden ayırın.
Bu nedenle, navController
'ü doğrudan herhangi bir bileşene değil, gezinme geri çağırma işlevlerini parametre olarak iletmeniz gerekir. Bu sayede, testlerde navController
örneği gerektirmediğinden tüm bileşenlerinizin ayrı ayrı test edilmesi sağlanır.
composable
lambda tarafından sağlanan dolaylı çağrı düzeyi, gezinme kodunuzu kompozit öğenin kendisinden ayırmanıza olanak tanır. Bu yöntem iki yönde çalışır:
- Yalnızca ayrıştırılmış bağımsız değişkenleri composable öğenize iletin
- Gezinmek için
NavController
yerine, composable tarafından tetiklenmesi gereken lambda'ları iletin.
Örneğin, giriş olarak userId
alan ve kullanıcıların bir arkadaşın profil sayfasına gitmesine olanak tanıyan bir ProfileScreen
bileşeninin imzası şu şekilde olabilir:
@Composable
fun ProfileScreen(
userId: String,
navigateToFriendProfile: (friendUserId: String) -> Unit
) {
…
}
Bu sayede, ProfileScreen
bileşeni Gezinme'den bağımsız olarak çalışır ve bağımsız olarak test edilebilir. composable
lambda, gezinme API'leri ile bileşeniniz 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
öğesini, composable'larınıza iletilen gezinme işlemlerini ve bağımsız ekran composable'larınızı test ederek uygulamada gezinme gereksinimlerinizi karşılayan testler yazmanız önerilir.
NavHost
test ediliyor
NavHost
öğenizi 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'a sarmalayın.
@Composable
fun AppNavHost(navController: NavHostController){
NavHost(navController = navController){ ... }
}
Artık gezinme testi yapısının bir örneğini TestNavHostController
ileterek AppNavHost
öğesini ve NavHost
içinde tanımlanan tüm gezinme mantığını test edebilirsiniz. Uygulamanızın ve NavHost
'ün başlangıç hedefini doğrulayan bir kullanıcı arayüzü testi şöyle 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ü öğelerine tıklayarak ve ardından görüntülenen hedefi doğrulayarak veya beklenen rotayı mevcut rotayla karşılaştırarak navigasyon uygulamanızı çeşitli şekillerde test edebilirsiniz.
Uygulamanızın uygulamasını test etmek istediğiniz için kullanıcı arayüzündeki tıklamalar tercih edilir. Bunu, tek tek derlenebilir işlevlerle birlikte nasıl tek başına test edeceğinizi öğrenmek için Jetpack Compose'da test etme codelab'ine göz atın.
Ayrıca, navController
'ın currentBackStackEntry
özelliğini kullanarak mevcut rotayı beklenen modelle karşılaştırarak iddialarınızı kontrol etmek için navController
'i de kullanabilirsiniz:
@Test
fun appNavHost_clickAllProfiles_navigateToProfiles() {
composeTestRule.onNodeWithContentDescription("All Profiles")
.performScrollTo()
.performClick()
assertTrue(navController.currentBackStackEntry?.destination?.hasRoute<Profile>() ?: false)
}
Compose testiyle ilgili temel bilgiler hakkında daha fazla bilgi için Compose düzeninizi test etme başlıklı makaleyi ve Jetpack Compose'da test etme codelab'ini inceleyin. Gezinme kodunu ileri düzey test etme hakkında daha fazla bilgi edinmek için Gezinme Testi kılavuzunu ziyaret edin.
Daha fazla bilgi
Jetpack Gezinme hakkında daha fazla bilgi edinmek için Gezinme bileşenini kullanmaya başlama başlıklı makaleyi inceleyin veya Jetpack Compose Gezinme kod laboratuvarını tamamlayın.
Uygulamanızın gezinme menüsünü farklı ekran boyutlarına, yönlere ve form faktörlerine uyum sağlayacak şekilde nasıl tasarlayacağınızı öğrenmek için Duyarlı kullanıcı arayüzleri için gezinme başlıklı makaleyi inceleyin.
Modüler hale getirilmiş bir uygulamada, iç içe yerleştirilmiş grafikler ve alt gezinme çubuğu entegrasyonu gibi kavramlar dahil olmak üzere daha gelişmiş bir Compose gezinme uygulaması hakkında bilgi edinmek için 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
- Oluşturma bölümündeki Material Design 2
- Jetpack Gezinmeyi Gezinme Oluşturmaya Taşıma
- Durum bilgisini nerede gösterebilirim?