Parçalar ve Kotlin DSL

Gezinme bileşeni, Kotlin tabanlı alana özgü bir dil sağlar veya Kotlin'in type-safe parametresini temel alan DSL inşaatçılar , Bu API, grafiğinizi bildirerek oluşturmak yerine Kotlin kodunuzda oluşturmanıza olanak tanır daha kolay olur. Bu, uygulamanızın özel bir kitle oluşturmak gezinmeyi kolaylaştırır. Örneğin, uygulamanız bir harici bir web hizmetinden gezinme yapılandırmasını dinamik olarak bir gezinme grafiği oluşturmak için onCreate() işlevi.

Bağımlılıklar

Kotlin DSL'yi Parçalarla birlikte kullanmak için aşağıdaki bağımlılığı uygulamanızın build.gradle dosyası:

Eski

dependencies {
    def nav_version = "2.8.0"

    api "androidx.navigation:navigation-fragment-ktx:$nav_version"
}

Kotlin

dependencies {
    val nav_version = "2.8.0"

    api("androidx.navigation:navigation-fragment-ktx:$nav_version")
}

Grafik oluşturma

Burada, Google Ads kurallarından yola çıkarak hazırlanan Sunflower uygulamasında gösterilir. Bunun için Örneğin, iki hedefimiz var: home ve plant_detail. home Hedef, kullanıcı uygulamayı ilk kez başlattığında mevcuttur. Bu hedef kullanıcının bahçesindeki bitkilerin bir listesini görüntüler. Kullanıcı bitkiler olduğunda uygulama plant_detail hedefine gidiyor.

Şekil 1'de bu hedefler, Uygulamanın kullandığı plant_detail hedef ve bir işlem (to_plant_detail) home - plant_detail arası rotayı izleyin.

Sunflower uygulamasının iki hedefi ve
            şekilde bağdaştırır.
Şekil 1. Sunflower uygulamasının iki hedefi vardır: home ve plant_detail ile birlikte şu işlemi gerçekleştiren bir işlem: birbirine bağlar.

Kotlin DSL Nav Grafiği Barındırma

Uygulamanızın gezinme grafiğini oluşturabilmek için öncelikle grafiğe dönüştürülebilir. Bu örnekte parçalar kullanıldığı için, grafiği NavHostFragment bir FragmentContainerView:

<!-- activity_garden.xml -->
<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <androidx.fragment.app.FragmentContainerView
        android:id="@+id/nav_host"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:defaultNavHost="true" />

</FrameLayout>

Bu örnekte app:navGraph özelliğinin ayarlanmadığına dikkat edin. Grafik bir kaynak olarak tanımlanmadığından res/navigation klasörü olduğundan onCreate() öğesinin bir parçası olarak ayarlanması gerekir bu etkinliği takip etmeniz gerekir.

XML'de, bir işlem hedef kimliğini bir veya daha fazla bağımsız değişkenle birbirine bağlar. Ancak, Navigasyon DSL'sini kullanırken bir rota, yol gösterir. Yani DSL'yi kullanırken işlem kavramı yoktur.

Bir sonraki adım, işletme hedefinizi tanımlarken kullanacağınız rotaları grafiğe dönüştürülebilir.

Grafiğiniz için rota oluşturun

XML tabanlı gezinme grafikleri, bir üründen diğerine adımına geçelim. Her id için sayısal bir sabit sayı oluşturulur özelliğinin değeri. Derleme zamanında oluşturulan bu statik kimlikler Böylece, Gezinme DSL'sini kullanmak için çalışma zamanında gezinme grafiğinizi oluştururken kullanabilirsiniz. serialize edilebilir türler yerine Kimlikler. Her rota, benzersiz bir türle temsil edilir.

Bağımsız değişkenlerle çalışırken, bunlar rotaya eklenir türü ekleyin. Bu şekilde güvenli yazın. kullanabilirsiniz.

@Serializable data object Home
@Serializable data class Plant(val id: String)

Güzergahlarınızı tanımladıktan sonra, gezinme grafiğini oluşturabilirsiniz.

val navController = findNavController(R.id.nav_host_fragment)
navController.graph = navController.createGraph(
    startDestination = Home
) {
    fragment<HomeFragment, Home> {
        label = resources.getString(R.string.home_title)
    }
    fragment<PlantDetailFragment, PlantDetail> {
        label = resources.getString(R.string.plant_detail_title)
    }
}

Bu örnekte, iki parçalı hedef fragment() DSL oluşturucu işlevi. Bu işlev, iki tür gerektirir bağımsız değişkenler ,

Önce bir Fragment sınıfı API'yi kullanabilirsiniz. Bunu ayarlamak tanımlanmış parça hedeflerde android:name özelliğini ayarlayarak anlamına gelir.

İkincisi, rota. Bu, Any tarihinden itibaren seri hale getirilebilir bir tür olmalıdır. Google bu hedef tarafından kullanılacak gezinme bağımsız değişkenlerini içermelidir. ve türlerini inceleyelim.

İşlev ayrıca, ve özel öğeler için yerleşik oluşturucu işlevlerinin yanı sıra argümanlar ve derin bağlantılar.

Son olarak, home konumundan plant_detail konumuna gitmek için şu dosyayı kullanabilirsiniz: NavController.navigate() şunu arar:

private fun navigateToPlant(plantId: String) {
   findNavController().navigate(route = PlantDetail(id = plantId))
}

PlantDetailFragment işlevinde, geçerli NavBackStackEntry ve sesli arama yapıyorum toRoute çift tıklayın.

val plantDetailRoute = findNavController().getBackStackEntry<PlantDetail>().toRoute<PlantDetail>()
val plantId = plantDetailRoute.id

PlantDetailFragment, ViewModel kullanıyorsa rota örneğini şunu kullanarak alın: SavedStateHandle.toRoute.

val plantDetailRoute = savedStateHandle.toRoute<PlantDetail>()
val plantId = plantDetailRoute.id

Bu kılavuzun geri kalanında, yaygın olarak kullanılan gezinme grafiği öğeleri, hedefler, bunları nasıl kullanacağınızı öğreneceksiniz.

Hedefler

Kotlin DSL, üç hedef türü için yerleşik destek sağlar: Her biri kendine ait olan Fragment, Activity ve NavGraph hedefleri oluşturmak ve yapılandırmak için kullanılabilen satır içi uzantı işlevi seçeceğiz.

Parça hedefleri

İlgili içeriği oluşturmak için kullanılan fragment() DSL işlevi, kullanıcı arayüzünün parça sınıfı ve bu hedefi benzersiz şekilde tanımlamak için kullanılan rota türü ve ardından bir lambda Burada açıklandığı gibi ek yapılandırma sağlayabileceğiniz yöntem Kotlin DSL grafiğiniz bölümünde görünür.

fragment<MyFragment, MyRoute> {
   label = getString(R.string.fragment_title)
   // custom argument types, deepLinks
}

Aktivite hedefi

İlgili içeriği oluşturmak için kullanılan activity() DSL işlevi, rota için bir tür parametresi alır ancak tüm etkinlik sınıflarını içerir. Bunun yerine, anahtar kelimeler için isteğe bağlı bir activityClass bir lambda var. Bu esneklik sayesinde etkinlik hedefi tanımlayabilirsiniz. dolaylı bir istek kullanılarak başlatılması gereken intent değeri kullanıldığında açıkça daha anlaşılır hale gelemez. Parça hedeflerde olduğu gibi, Etiket, özel bağımsız değişkenler ve derin bağlantılar yapılandırabilirsiniz.

activity<MyRoute> {
   label = getString(R.string.activity_title)
   // custom argument types, deepLinks...

   activityClass = MyActivity::class
}

İlgili içeriği oluşturmak için kullanılan navigation() DSL işlevi, iç içe yerleştirilmiş bir gezinme oluşturmak için kullanılabilir grafiği'ne dokunun. Bu işlev bir tür alır parametresini kullanabilirsiniz. Ayrıca iki bağımsız değişken gerekir: grafiğin başlangıç hedefinin rotası ve ileri doğru giden bir lambda Grafiği yapılandırın. Geçerli öğeler arasında diğer hedefler, özel bağımsız değişken yer alır derin bağlantılar ve bu sayfa için açıklayıcı bir etiket hedef. Bu etiket, aşağıdakileri kullanarak gezinme grafiğini kullanıcı arayüzü bileşenlerine bağlamak için yararlı olabilir: NavigationUI.

@Serializable data object HomeGraph
@Serializable data object Home

navigation<HomeGraph>(startDestination = Home) {
   // label, other destinations, deep links
}

Özel hedefleri destekleme

Yeni bir hedef türü kullanıyorsanız doğrudan Kotlin DSL'yi desteklemeyense bu hedefleri kullanarak Kotlin DSL'nizi addDestination():

// The NavigatorProvider is retrieved from the NavController
val customDestination = navigatorProvider[CustomNavigator::class].createDestination().apply {
    route = Graph.CustomDestination.route
}
addDestination(customDestination)

Alternatif olarak, tekli artı operatörünü yeni bir oluşturulan hedefi grafiğe doğrudan ekleyin:

// The NavigatorProvider is retrieved from the NavController
+navigatorProvider[CustomNavigator::class].createDestination().apply {
    route = Graph.CustomDestination.route
}

Hedef bağımsız değişkenleri sağlama

Hedef bağımsız değişkenleri, rota sınıfının bir parçası olarak tanımlanabilir. Bunlar, herhangi bir Kotlin sınıfı için belirtilen şekilde tanımlanabilir. Gerekli bağımsız değişkenler boş değerli olmayan türler olarak tanımlanır ve isteğe bağlı bağımsız değişkenler varsayılan olarak tanımlanır değerler.

Rotaları ve bunların bağımsız değişkenlerini göstermek için kullanılan temel mekanizma dizedir. kullanır. Rotaları modellemek için dize kullanmak, gezinme durumunun depolanmasını ve yapılandırma sırasında diskten geri yüklendi sistem tarafından başlatılan ve işlem ölüm ile ilişkilendirilebilir. İşte bu nedenle Her gezinme bağımsız değişkeni serileştirilebilir olmalıdır; yani, bağımsız değişken değerinin bellek içi gösterimini String

Kotlin serileştirmesi eklenti Google Analytics 4'teki temel alan anahtar kelimeler @Serializable ek açıklaması bir nesneye eklendi.

@Serializable
data class MyRoute(
  val id: String,
  val myList: List<Int>,
  val optionalArg: String? = null
)

fragment<MyFragment, MyRoute>

Özel türler sağlama

Özel bağımsız değişken türleri için özel bir NavType sınıfı sağlamanız gerekir. Bu , türünüzün bir rotadan veya derin bağlantıdan tam olarak nasıl ayrıştırıldığını kontrol etmenize olanak tanır.

Örneğin, bir arama ekranını tanımlamak için kullanılan bir rota, şu özelliklere sahip bir sınıfı içerebilir: şu arama parametrelerini temsil eder:

@Serializable
data class SearchRoute(val parameters: SearchParameters)

@Serializable
data class SearchParameters(
  val searchQuery: String,
  val filters: List<String>
)

Özel NavType şöyle yazılabilir:

val SearchParametersType = object : NavType<SearchParameters>(
  isNullableAllowed = false
) {
  override fun put(bundle: Bundle, key: String, value: SearchParameters) {
    bundle.putParcelable(key, value)
  }
  override fun get(bundle: Bundle, key: String): SearchParameters {
    return bundle.getParcelable(key) as SearchParameters
  }

  override fun serializeAsValue(value: SearchParameters): String {
    // Serialized values must always be Uri encoded
    return Uri.encode(Json.encodeToString(value))
  }

  override fun parseValue(value: String): SearchParameters {
    // Navigation takes care of decoding the string
    // before passing it to parseValue()
    return Json.decodeFromString<SearchParameters>(value)
  }
}

Bu, daha sonra Kotlin DSL'nizde diğer türler gibi kullanılabilir:

fragment<SearchFragment, SearchRoute> {
    label = getString(R.string.plant_search_title)
    typeMap = mapOf(typeOf<SearchParameters>() to SearchParametersType)
}

Hedefe giderken rotanızın bir örneğini oluşturun:

val params = SearchParameters("rose", listOf("available"))
navController.navigate(route = SearchRoute(params))

Parametre, hedefteki rotadan edinilebilir:

val searchRoute = navController().getBackStackEntry<SearchRoute>().toRoute<SearchRoute>()
val params = searchRoute.parameters

Derin bağlantılar

Derin bağlantılar, XML ile desteklenen herhangi bir hedefe eklenebilir. gezinme grafiğidir. Derin bağlantı oluşturma bölümünde belirtilen prosedürlerin tümü sürece uygulanır. bir derin bağlantı oluşturmayı öğreneceksiniz.

Dolaylı derin bağlantı oluştururken ancak o zaman hangisi için analiz edilebilecek bir XML gezinme kaynağınız yoksa <deepLink> öğeleri. Bu nedenle, <nav-graph> öğesi; AndroidManifest.xml dosyanıza intent filtreler ekleyebilirsiniz. Amaç sağladığınız filtrenin temel yolu, işlemi ve mime türüyle uygulamanızın derin bağlantılarını kullanın.

Derin bağlantılar, bir hedefe, içindeki deepLink işlevi çağırılarak eklenir lambda var. Rotayı parametreleştirilmiş bir tür olarak kabul eder ve basePath parametresini kullanın.

Ayrıca, deepLinkBuilder lambda var.

Aşağıdaki örnek, Home hedefi için bir derin bağlantı URI'si oluşturmaktadır.

@Serializable data object Home

fragment<HomeFragment, Home>{
  deepLink<Home>(basePath = "www.example.com/home"){
    // Optionally, specify the action and/or mime type that this destination
    // supports
    action = "android.intent.action.MY_ACTION"
    mimeType = "image/*"
  }
}

URI biçimi

Derin bağlantı URI'si biçimi, rotanın alanlarından otomatik olarak oluşturulur kullanarak aşağıdaki kuralları kullanabilirsiniz:

  • Gerekli parametreler yol parametreleri olarak eklenmiştir (örnek: /{id})
  • Varsayılan değere sahip parametreler (isteğe bağlı parametreler) query olarak eklenir parametreleri (örnek: ?name={name})
  • Koleksiyonlar sorgu parametreleri olarak eklenir (örnek: ?items={value1}&items={value2})
  • Parametrelerin sırası, rotadaki alanların sıralamasıyla eşleşir

Örneğin, şu rota türü:

@Serializable data class PlantDetail(
  val id: String,
  val name: String,
  val colors: List<String>,
  val latinName: String? = null,
)

şu şekilde oluşturulmuş bir URI biçimine sahiptir:

basePath/{id}/{name}/?colors={color1}&colors={color2}&latinName={latinName}

Ekleyebileceğiniz derin bağlantı sayısıyla ilgili bir sınır yoktur. Her aradığınızda deepLink() o hedef için tutulan listeye yeni bir derin bağlantı eklenir.

Sınırlamalar

Güvenli Bağımsız Değişkenler eklentisi Kotlin DSL ile uyumlu değildir. Bunun nedeni, eklentinin Directions ve Arguments sınıflarını oluşturabilirsiniz.