フラグメントと Kotlin DSL

Navigation コンポーネントは、Kotlin ベースのドメイン固有の言語、つまり DSL は、Kotlin のタイプセーフな ビルダー をタップします。この API を使用すると、Kotlin コードでグラフを宣言的に構成できます。 XML リソース内よりも効率的です。これは、アプリケーションの開発やテストを行う 動的ナビゲーションですたとえば、アプリはインターネットからダウンロードし、 ナビゲーション設定を作成し、それを使用して 設定を使用して、アクティビティの onCreate() 関数を使用します。

依存関係

Fragment で Kotlin DSL を使用するには、アプリの build.gradle ファイル:

Groovy

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

グラフを作成する

このスライドは、Sunflower アプリ。今回 たとえば、homeplant_detail の 2 つのデスティネーションがあります。home デスティネーションは、ユーザーがアプリを初めて起動したときに表示され、ユーザーの庭にある植物のリストを示します。ユーザーが植物の 1 つを選択すると、アプリは plant_detail デスティネーションに移動します。

図 1 に、これらのディスティネーションと、アプリが home から plant_detail に移動する際に使用するアクション to_plant_detail と、plant_detail デスティネーションで必要となる引数を示します。

Sunflower アプリの 2 つのデスティネーションと、それらを接続するアクション。
図 1: Sunflower アプリの homeplant_detail の 2 つのデスティネーションと、それらを接続するアクション。

Kotlin DSL ナビゲーション グラフをホストする

アプリのナビゲーション グラフを作成する前に、アプリのナビゲーション グラフをホストする場所が必要です。 表示されます。この例ではフラグメントを使用して、グラフを FragmentContainerView 内の NavHostFragment にホストします。

<!-- 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>

この例では app:navGraph 属性が設定されていないことに注意してください。グラフ リソースとして定義されていない res/navigation フォルダに移動するため、onCreate() の一部として設定する必要があります。 必要があります。

XML では、アクションはデスティネーション ID を 1 つ以上の引数と関連付けます。ただし、Navigation DSL を使用する場合はルートに引数をモジュールの一部として 表示されます。つまり、DSL を使用する場合はアクションという概念はありません。

次に、サービス アカウントを定義するときに使用するルートを 表示されます。

グラフのルートを作成する

XML ベースのナビゲーション グラフは、 説明しました。数値定数は id ごとに作成されます。 属性を定義します。ビルド時に生成される静的 ID は、 使用できるため、Navigation DSL データセットが serialization を使用 を の代わりに あります。各ルートは一意のタイプで表されます。

引数を処理するときに、これらはルートに組み込まれます。 type。これにより、型安全性が確保されます。 使用します。

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

ルートを定義したら、ナビゲーション グラフを作成できます。

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

この例では、2 つのフラグメント デスティネーションが、 fragment() DSL ビルダー関数。この関数には 2 つの 引数 をタップします。

1 つ目は Fragment クラスです。 このデスティネーションの UI を提供しますこれを設定しても 定義されているフラグメント デスティネーションに android:name 属性を設定する 必要があります。

2 つ目は経路ですこれは、Any から拡張されたシリアル化可能な型でなければなりません。これは、 このデスティネーションで使用されるナビゲーション引数を含めます。 定義できます。

この関数は、次のような追加構成用のオプションのラムダも受け入れます。 カスタム引数用の埋め込みビルダー関数も用意されています。 ディープリンクが含まれます

最後に、次のコマンドを使用して home から plant_detail に移動します。 NavController.navigate() 呼び出し:

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

PlantDetailFragment では、ナビゲーション引数を取得するために以下を取得します。 現在の NavBackStackEntry 通話 toRoute ルート インスタンスを取得します。

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

PlantDetailFragmentViewModel を使用している場合は、次のコマンドを使用してルート インスタンスを取得します。 SavedStateHandle.toRoute

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

このガイドの残りの部分では、一般的なナビゲーション グラフの要素、デスティネーション、グラフの作成時にそれらを使用する方法について説明します。

デスティネーション

Kotlin DSL には、FragmentActivityNavGraph という 3 つのデスティネーション タイプのサポートが組み込まれています。各デスティネーションには、デスティネーションの作成と構成に使用できる独自のインライン拡張関数があります。

Fragment デスティネーション

fragment() DSL 関数は、UI のフラグメント クラスと このデスティネーションを一意に識別するために使用されるルートタイプの後にラムダが続きます 追加の構成を行うことができます。詳細については、 Kotlin DSL グラフを使用する」セクションを参照してください。

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

Activity デスティネーション

activity() DSL 関数はルートの型パラメータを受け取りますが、 実装します。代わりに、オプションの activityClass を 後置ラムダを使用しますこの柔軟性により、サービス アカウントに対するアクティビティのデスティネーションを定義し、 暗黙的な依存関係を使用して起動する必要があるアクティビティを、 意味がありません。フラグメント デスティネーションと同様に、 ラベル、カスタム引数、ディープリンクを設定できます。

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

   activityClass = MyActivity::class
}

navigation() DSL 関数を使用してネストされたナビゲーションを作成 グラフをご覧ください。この関数は パラメータを指定します。また、この関数は次の 2 つの引数を取ります。 グラフの開始デスティネーションのルートと、そのパスをさらに グラフを設定します。有効な要素には、他のデスティネーション、カスタム引数などがあります ディープリンク、商品の説明ラベル destination を使用します。 このラベルは、Terraform を使用して、ナビゲーション グラフを UI コンポーネントにバインドする場合に便利です。 NavigationUI

@Serializable data object HomeGraph
@Serializable data object Home

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

カスタム デスティネーションのサポート

新しいデスティネーション タイプを使用している場合 サポートしていない場合、これらのデスティネーションを Kotlin DSL を addDestination():

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

別の方法としては、単項プラス演算子を使用して、新しく作成されたデスティネーションを直接グラフに追加することもできます。

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

デスティネーション引数を提供する

デスティネーションの引数は、ルートクラスの一部として定義できます。これらは次のいずれかです。 他の Kotlin クラスと同じように定義できます。必須の引数は次のとおりです。 null 値非許容型として定義され、オプションの引数はデフォルト 使用できます。

ルートとその引数を表すための基礎となるメカニズムは文字列です。 基づいています。文字列を使用して経路をモデル化することで、ナビゲーション状態を保存し、 構成中にディスクから復元される 変更システムが開始したプロセス 防ぐことができます。このため、 各ナビゲーション引数はシリアル化可能である必要があります。つまり、 このメソッドは、引数値のメモリ内表現を String

Kotlin のシリアル化は プラグイン 基本的なシリアル化のメソッドを自動生成 場合、 @Serializable アノテーションがオブジェクトに追加されます。

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

fragment<MyFragment, MyRoute>

カスタム型を指定する

カスタム引数型の場合は、カスタム NavType クラスを指定する必要があります。この を使用すると、ルートまたはディープリンクからタイプの解析方法を正確に制御できます。

たとえば、検索画面を定義するために使用されるルートに、 検索パラメータを表します。

@Serializable
data class SearchRoute(val parameters: SearchParameters)

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

カスタム NavType は次のように記述できます。

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

その後、その他の型と同様に Kotlin DSL で使用できます。

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

目的地に移動する際は、ルートのインスタンスを作成します。

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

このパラメータは、デスティネーションのルートから取得できます。

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

ディープリンク

ディープリンクは XML によるナビゲーション グラフと同様に、どのデスティネーションにも追加できます。ディープリンクの作成に関する手順と同じ 適用対象はプロセスに適用されます。 基本的な手順について学びます。

暗黙的ディープリンクを作成する場合 しかし、分析可能な XML ナビゲーション リソースがないので、 <deepLink> 要素。そのため、<nav-graph> を配置できない 要素を AndroidManifest.xml ファイル内で指定し、代わりに intent を追加する必要があります アクティビティに手動でフィルタを適用できます。インテント 指定するフィルタは、API のベースパス、アクション、および mimetype と一致する必要があります。 ディープリンクを設定します

デスティネーションにディープリンクを追加するには、内部で deepLink 関数を呼び出します。 渡します。これはパラメータ化された型としてルートを受け入れ、 パラメータ basePath には、ディープリンクに使用される URL のベースパスを指定します。

また、 deepLinkBuilder 後置ラムダ。

次の例では、デスティネーション Home へのディープリンク URI が作成されます。

@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 形式

ディープリンク URI 形式は、ルートのフィールドから自動的に生成されます 次のルールを使用します。

  • 必須パラメータはパスパラメータとして追加されます(例: /{id})。
  • デフォルト値を持つパラメータ(オプションのパラメータ)は、クエリ parameters(例: ?name={name}
  • コレクションはクエリ パラメータとして追加されます(例: ?items={value1}&items={value2})
  • パラメータの順序はルート内のフィールドの順序と一致します。

たとえば、次のルートタイプがあるとします。

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

生成される URI 形式は次のとおりです。

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

追加できるディープリンクの数に制限はありません。deepLink() を呼び出すたびに、そのデスティネーションで保持されているリストに新しいディープリンクが追加されます。

制限事項

Safe Args プラグインは、Directions クラスと Arguments クラスを生成する XML リソース ファイルを参照するため、Kotlin DSL とは互換性がありません。