Oluşturma özelliğiyle gezinme

Gezinme bileşeni, Jetpack için destek sağlar Uygulamalar oluşturun. composable'lar arasında gezinebilirsiniz. ve Navigasyon bileşeninin altyapısından ve özellikleri.

Kurulum

Compose'u desteklemek için uygulama modülünüzün build.gradle dosyası:

Modern

dependencies {
    def nav_version = "2.7.7"

    implementation "androidx.navigation:navigation-compose:$nav_version"
}

Kotlin

dependencies {
    val nav_version = "2.7.7"

    implementation("androidx.navigation:navigation-compose:$nav_version")
}

Başlayın

Uygulamada gezinmeyi uygularken bir gezinme ana makinesi uygulayın. grafik ve denetleyicidir. Daha fazla bilgi için Gezinmeye genel bakış bölümünü inceleyin.

Compose'da NavController oluşturma hakkında bilgi için Oluşturma bölümüne bakın Gezinme denetleyicisi oluşturma başlıklı makalenin bölümüne bakın.

NavHost oluşturma

Compose'da NavHost oluşturma hakkında bilgi için Oluştur bölümüne bakın Gezinme grafiğinizi tasarlama başlıklı makaleye göz atın.

Bir Oluşturulabilir öğeye gitme hakkında bilgi edinmek için bkz. Bir hedef ekleyin belgelerinden faydalanabilirsiniz.

Gezinme Oluşturma, ayrıca composable arasında bağımsız değişkenlerin aktarılmasını da destekler hedefler. Bunu yapmak için URL'nize bağımsız değişken yer tutucuları derin bir dosyaya bağımsız değişkenler eklemeye benzer bağlantısını gezinme kitaplığı:

NavHost(startDestination = "profile/{userId}") {
    ...
    composable("profile/{userId}") {...}
}

Varsayılan olarak, tüm bağımsız değişkenler dize olarak ayrıştırılır. Şu parametrenin arguments parametresi: composable(), NamedNavArgument nesnelerinin listesini kabul ediyor. Şunları yapabilirsiniz: navArgument() yöntemini kullanarak hızlıca bir NamedNavArgument oluşturabilir ve ardından tam type değerini belirtin:

NavHost(startDestination = "profile/{userId}") {
    ...
    composable(
        "profile/{userId}",
        arguments = listOf(navArgument("userId") { type = NavType.StringType })
    ) {...}
}

NavBackStackEntry öğesindeki bağımsız değişkenleri ayıklamanız gerekir. composable() işlevinin lambda'sında kullanılabilir.

composable("profile/{userId}") { backStackEntry ->
    Profile(navController, backStackEntry.arguments?.getString("userId"))
}

Bağımsız değişkeni hedefe iletmek için URL'yi rotaya eklemeniz gerekir navigate çağrısı yaptığınızda:

navController.navigate("profile/user1234")

Desteklenen türlerin listesi için Verileri şu öğeler arasında iletme: hedefler.

Navigasyon sırasında karmaşık verileri alma

Gezinirken karmaşık veri nesnelerini geçmemeniz önemle tavsiye edilir. Bunun yerine, benzersiz tanımlayıcı gibi gerekli minimum bilgiyi veya başka türden bir kimlik (ör. gezinme işlemleri gerçekleştirilirken bağımsız değişken olarak):

// Pass only the user ID when navigating to a new destination as argument
navController.navigate("profile/user1234")

Karmaşık nesneler, örneğin veri katmanından yararlanın. Rotayı izledikten sonra hedefinize vardıktan sonra, kimlik iletildi. ViewModel içinde aşağıdakilerden sorumlu bağımsız değişkenleri almak için: veri katmanına erişmek için ViewModel SavedStateHandle öğesini kullanın:

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)

// …

}

Bu yaklaşım, yapılandırma değişiklikleri ve olası yapılandırma değişiklikleri sırasında söz konusu nesne güncellenirken veya dönüştürüldüğünde gerçekleşen tutarsızlıklar.

Neden karmaşık verileri olduğu gibi iletmekten kaçınmanız gerektiği ve desteklenen bağımsız değişken türlerinin listesini görmek için hedefler.

İsteğe bağlı bağımsız değişkenler ekleyin

Gezinme Oluşturma, isteğe bağlı gezinme bağımsız değişkenlerini de destekler. İsteğe bağlı bağımsız değişkenlerden iki açıdan farklıdır:

  • Sorgu parametresi söz dizimi ("?argName={argName}") kullanılarak eklenmelidir
  • Bunların defaultValue grubu veya nullable = true olması gerekir (varsayılan değer dolaylı olarak null değerine ayarlanır)

Bu, isteğe bağlı tüm bağımsız değişkenlerin Liste olarak composable() işlevi:

composable(
    "profile?userId={userId}",
    arguments = listOf(navArgument("userId") { defaultValue = "user1234" })
) { backStackEntry ->
    Profile(navController, backStackEntry.arguments?.getString("userId"))
}

Artık hedefe hiçbir bağımsız değişken aktarılmamış olsa bile defaultValue, bunun yerine "user1234" kullanılır.

Rotalar aracılığıyla bağımsız değişkenleri ele alma yapısı, composable'lar, Navigasyon'dan tamamen bağımsızdır ve kendilerini test edilebilir.

Gezinme Oluşturma, oluşturulan örtülü derin bağlantıları, composable() işlevi de dahildir. deepLinks parametresi NavDeepLink nesneleri bunlar için navDeepLink() yöntemi:

val uri = "https://www.example.com"

composable(
    "profile?id={id}",
    deepLinks = listOf(navDeepLink { uriPattern = "$uri/{id}" })
) { backStackEntry ->
    Profile(navController, backStackEntry.arguments?.getString("id"))
}

Bu derin bağlantılar, belirli bir URL'yi, işlemi veya MIME türünü bir composable'dan bahsetmek istiyorum. Varsayılan olarak, bu derin bağlantılar harici uygulamalara gösterilmez. Alıcı: bu derin bağlantıları harici olarak kullanılabilir hale getirmek için <intent-filter> öğelerini uygulamanızın manifest.xml dosyasına ekleyin. Derin bağlantılar bağlantısı varsa aşağıdakini Manifestin <activity> öğesi:

<activity …>
  <intent-filter>
    ...
    <data android:scheme="https" android:host="www.example.com" />
  </intent-filter>
</activity>

Gezinme derin bağlantı olduğunda, otomatik olarak söz konusu composable'a giden derin bağlantılara başka bir uygulama tarafından tetiklenir.

Aynı derin bağlantılar, aynı zamanda bir PendingIntent oluşturmak için bir composable'dan uygun derin bağlantı:

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)
}

Daha sonra bu deepLinkPendingIntent öğesini diğer PendingIntent gibi kullanabilirsiniz: Derin bağlantı hedefinde uygulamanızı açın.

İç İçe Navigasyon

İç içe gezinme grafikleri oluşturma hakkında bilgi için bkz. İç içe yerleştirilmiş grafikler.

Alttaki gezinme çubuğuyla entegrasyon

NavController öğesini, composable hiyerarşinizde daha üst bir düzeyde tanımlayarak Navigasyon'u, alt gezinme bölümü ve diğer bileşenlere bir bileşenidir. Bu işlem, ekranın alt kısmındaki simgeleri seçerek gezinmenize olanak tanır. çubuk.

BottomNavigation ve BottomNavigationItem bileşenlerini kullanmak için: androidx.compose.material bağımlılığını Android uygulamanıza ekleyin.

Modern

dependencies {
    implementation "androidx.compose.material:material:1.6.8"
}

android {
    buildFeatures {
        compose true
    }

    composeOptions {
        kotlinCompilerExtensionVersion = "1.5.15"
    }

    kotlinOptions {
        jvmTarget = "1.8"
    }
}

Kotlin

dependencies {
    implementation("androidx.compose.material:material:1.6.8")
}

android {
    buildFeatures {
        compose = true
    }

    composeOptions {
        kotlinCompilerExtensionVersion = "1.5.15"
    }

    kotlinOptions {
        jvmTarget = "1.8"
    }
}

Alttaki gezinme çubuğundaki öğeleri gezinme grafiğinizdeki rotalara bağlamak için: Burada görülen Screen gibi mühürlü bir sınıf tanımlamanız önerilir. rotayı ve hedeflerin Dize kaynak kimliğini içerir.

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)
}

Ardından bu öğeleri, BottomNavigationItem:

val items = listOf(
   Screen.Profile,
   Screen.FriendsList,
)

BottomNavigation composable'ınızda mevcut NavBackStackEntry öğesini alın currentBackStackEntryAsState() işlevi kullanılır. Bu giriş size geçerli NavDestination erişimi. Her bir öğenin seçilen durumu Daha sonra BottomNavigationItem, öğenin rotası karşılaştırılarak belirlenebilir varış noktasının ve üst varış noktalarının rotası ile iç içe yerleştirilmiş gezinme kullanıyorsanız NavDestination hiyerarşisi.

Öğenin rotası, onClick lambda'yı bir çağrıya bağlamak için de kullanılır. navigate, böylece öğeye dokunduğunuzda ilgili öğeye gidilir. Şunu kullanarak: saveState ve restoreState flag'leri, bu işaretlerin durumu ve öğe doğru şekilde kaydedildi ve geri yüklendi öğeler.

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) }
  }
}

Burada NavController.currentBackStackEntryAsState() avantajından yararlanıyorsunuz. navController durumunu NavHost işlevinden kaldırma yöntemini ve BottomNavigation bileşeniyle paylaşın. Bu, BottomNavigation otomatik olarak en güncel duruma sahip olur.

Yazmada Gezinme'de güvenlik yazın

Bu sayfadaki kod tür için güvenli değil. navigate() hattını arayabilirsiniz var olmayan rotalar veya yanlış bağımsız değişkenlerle işlev görür. Ancak, gezinme kodunuzu çalışma zamanında tür açısından güvenli olacak şekilde yapılandırın. Bu şekilde şunları yapabilirsiniz: kilitlenmeleri önleyin ve şunlardan emin olun:

  • Bir hedef veya gezinme grafiğine giderken sağladığınız bağımsız değişkenler gerekli tüm bağımsız değişkenlerin mevcut olduğundan emin olun.
  • SavedStateHandle öğesinden aldığınız bağımsız değişkenler doğru türdedir.

Bu konuda daha fazla bilgi için Kotlin DSL'de ve Navigasyon'da tür güvenliği başlıklı makaleyi inceleyin. Oluştur'u tıklayın.

Birlikte çalışabilirlik

Oluştur ile Gezinme bileşenini kullanmak istiyorsanız iki seçeneğiniz vardır:

  • Parçalar için Gezinme bileşeniyle bir gezinme grafiği tanımlayın.
  • Oluşturma'da Oluştur'u kullanarak NavHost ile bir gezinme grafiği tanımlayın hedefler. Bu yalnızca gezinmedeki tüm ekranlar composable, composable.

Bu nedenle, karma Oluşturma ve Görünüm uygulamaları için öneri Parçaya dayalı Gezinme bileşeni. Parçalar daha sonra Görüntülemeye dayalı Ekranlar, Oluştur ekranları ve hem Görünümler hem de Oluştur özelliklerini kullanan ekranlar. Her biri Parçanın içerikleri Compose'da. Sonraki adım bu ekranları bağlamak oluşturma ve tüm Parçalar'ı kaldırma olanağı sağlar.

Oluşturma kodu içindeki hedefleri değiştirmek için şunları yapabilecek etkinlikleri kullanıma sunarsınız: hiyerarşideki herhangi bir composable'a geçirilebilir ve tetiklenebilir:

@Composable
fun MyScreen(onNavigate: (Int) -> Unit) {
    Button(onClick = { onNavigate(R.id.nav_profile) } { /* ... */ }
}

Parçanızda, Compose ile parça tabanlı arasındaki köprüyü NavController öğesini bulup hedef:

override fun onCreateView( /* ... */ ) {
    setContent {
        MyScreen(onNavigate = { dest -> findNavController().navigate(dest) })
    }
}

Alternatif olarak NavController öğesini Compose hiyerarşinizde aşağı aktarabilirsiniz. Ancak basit işlevlerin gösterilmesi çok daha fazla yeniden kullanılabilir ve test edilebilir.

Test

Testi etkinleştirmek için gezinme kodunu composable hedeflerinizden ayırın NavHost composable'dan ayrı olarak her composable'ı ayrı ayrı sunuyor.

Bu, navController öğesini doğrudan composable olarak ayarlayın ve bunun yerine gezinme geri çağırmalarını parametre olarak iletin. Bu da composable'ların test gerektirmesi ya da test edebilmeleri için testlerde navController örneği.

composable lambda'nın sağladığı dolaylı yoldan Gezinme kodunuzu composable'dan ayırın. Bu yöntem iki dilde çalışır: yol tarifi:

  • composable'ınıza yalnızca ayrıştırılan bağımsız değişkenleri iletin
  • Gezinmek için composable'ın tetiklemesi gereken lambda'ları iletin, NavController ile başlar.

Örneğin, giriş olarak userId alan veProfile kullanıcının, arkadaşının profil sayfasına gitmesi için aşağıdaki imzası bulunabilir:

@Composable
fun Profile(
    userId: String,
    navigateToFriendProfile: (friendUserId: String) -> Unit
) {
 
}

Bu şekilde, Profile composable, Navigasyon, Böylece bağımsız olarak test edilebilir. composable lambda Navigasyon ile süreç arasındaki boşluğu doldurmak için gereken API'ler ve composable'ınız:

composable(
    "profile?userId={userId}",
    arguments = listOf(navArgument("userId") { defaultValue = "user1234" })
) { backStackEntry ->
    Profile(backStackEntry.arguments?.getString("userId")) { friendUserId ->
        navController.navigate("profile?userId=$friendUserId")
    }
}

Uygulamada gezinme şartlarınızı kapsayan testler yazmanız önerilir NavHost test edildiğinde, gezinme işlemleri kendi ekran composable'larınıza kolayca erişebilmenizi sağlar.

NavHost test ediliyor

NavHost cihazınızı test etmeye başlamak için aşağıdaki gezinme testini ekleyin bağımlılık:

dependencies {
// ...
  androidTestImplementation "androidx.navigation:navigation-testing:$navigationVersion"
  // ...
}

NavHost test kişinizi oluşturabilir ve navController örneğinin bir örneğini burada görebilirsiniz. Bunun için gezinme test yapısı bir TestNavHostController sağlar. Kullanıcı arayüzü testi, uygulamanızın başlangıç hedefini doğrular ve NavHost şö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

Gezinme uygulamanızı çeşitli yollarla test edebilirsiniz: kullanıcı arayüzü öğelerini tıklar ve ardından, görüntülenen hedefi doğrulayarak veya beklenen rotayı mevcut rotayla karşılaştırarak kullanabilirsiniz.

Beton uygulamanızın uygulamasını test etmek istediğinizde, Kullanıcı arayüzleri tercih edilir. Bunu bağımsız composable ile birlikte test etmeyi öğrenmek için işlevlerini gerçekleştirdiğinden emin olmak için Jetpack Compose'da test codelab'i.

Onaylarınızı kontrol etmek için navController öğesini de kullanabilirsiniz. mevcut Dize rotasını beklenen rotayla karşılaştırarak navController adlı kullanıcının currentBackStackEntry cihazı:

@Test
fun appNavHost_clickAllProfiles_navigateToProfiles() {
    composeTestRule.onNodeWithContentDescription("All Profiles")
        .performScrollTo()
        .performClick()

    val route = navController.currentBackStackEntry?.destination?.route
    assertEquals(route, "profiles")
}

Oluşturma testiyle ilgili temel bilgiler hakkında daha fazla yardım için bkz. Compose düzeninizi test etme ve Jetpack Compose'da test etme codelab'e göz atın. Gezinme kodunu ileri düzey test etme hakkında daha fazla bilgi edinmek için Testte Gezinme rehberi.

Daha fazla bilgi

Jetpack Navigasyon hakkında daha fazla bilgi edinmek için bkz. Navigasyon'u kullanmaya başlama bileşenini kullanın veya Jetpack'i Gezinme codelab'i oluşturun.

Uygulamanızın gezinme deneyimini farklı ekranlara uyum sağlayacak şekilde nasıl tasarlayacağınızı öğrenmek için yönleri ve form faktörleri hakkında Duyarlı kullanıcı arayüzleri için gezinme.

E-Tablolar ve Google Haritalar'da daha gelişmiş bir Oluşturma gezinme uygulaması iç içe yerleştirilmiş grafikler ve alt gezinme çubuğu gibi kavramları içeren modülerleştirilmiş uygulama entegrasyonu için GitHub'da Now in Android uygulamasına göz atın.

Örnekler

ziyaret edin.