ナビゲーション グラフを設計する

Navigation コンポーネントでは、ナビゲーション グラフを使用してアプリのナビゲーションを管理します。ナビゲーション グラフとは、アプリ内の各デスティネーションと、それらの間の接続を含むデータ構造です。

デスティネーションのタイプ

デスティネーションの一般的なタイプとしては、ホストされているデスティネーション、アクティビティのデスティネーション、ダイアログのデスティネーションの 3 つがあります。次の表に、これら 3 つのデスティネーション タイプとその用途をまとめます。

タイプ

説明

使用場面

ホストされているデスティネーション

ナビゲーション ホスト全体を埋めるデスティネーションです。ホストされたデスティネーションのサイズはナビゲーション ホストのサイズと同じとなり、それ以前のデスティネーションは表示されなくなります。

メイン画面や詳細画面。

ダイアログのデスティネーション

オーバーレイ UI コンポーネントを表すデスティネーションです。この UI は、ナビゲーション ホストの場所やサイズには関連付けられません。それ以前のデスティネーションは、このデスティネーションの下に表示されます。

アラート、選択肢、フォーム。

アクティビティのデスティネーション

アプリ内の固有の画面または機能を表すデスティネーションです。

ナビゲーション グラフの終了ポイントとして機能し、Navigation コンポーネントとは別に管理されている新しい Android アクティビティを開始します。

最新の Android 開発では、アプリを 1 つのアクティビティで構成します。アクティビティのデスティネーションは、サードパーティ アクティビティとやり取りする場合や、移行プロセスの一部として使用するのが最適です。

このドキュメントでは、最も一般的で基本的なデスティネーションである「ホストされているデスティネーション」の例を示します。それ以外のデスティネーションについては、以下のガイドをご覧ください。

フレームワーク

どの場合にも同じ一般的なワークフローが適用されますが、ナビゲーション ホストとグラフの作成方法は使用する UI フレームワークによって異なります。

  • Compose で作成する: NavHost コンポーザブルを使用します。Kotlin DSL を使用して NavGraph を追加します。グラフは次の 2 つの方法で作成できます。
    • NavHost の一部として作成する: NavHost を追加する際に、その一部としてナビゲーション グラフを直接作成します。
    • プログラマティックに作成する: NavController.createGraph() メソッドを使用して NavGraph を作成し、直接 NavHost に渡します。
  • フラグメントを使用する: View UI フレームワークでフラグメントを使用する場合は、ホストとして NavHostFragment を使用します。ナビゲーション グラフはいくつかの方法で作成できます。
    • プログラマティックに作成する: Kotlin DSL を使用して NavGraph を作成し、NavHostFragment に直接適用します。
      • Kotlin DSL で使用する createGraph() 関数は、フラグメントでも Compose でも同じです。
    • XML で作成する: ナビゲーション ホストとグラフを XML で直接記述します。
    • Android Studio エディタ: Android Studio の GUI エディタを使用して、グラフを XML リソース ファイルとして作成、調整します。

Compose

Compose では、シリアル化可能なオブジェクトまたはクラスを使用してルートを定義します。ルートは、目的地への経路を記述し、目的地に必要なすべての情報を含みます。

@Serializable アノテーションを使用して、ルートタイプに必要なシリアル化メソッドとシリアル化解除メソッドを自動的に作成します。このアノテーションは、Kotlin シリアル化プラグインによって提供されます。こちらの手順に沿ってこのプラグインを追加します

ルートを定義したら、NavHost コンポーザブルを使用してナビゲーション グラフを作成します。次の例を考えてみましょう。

@Serializable
object Profile
@Serializable
object FriendsList

val navController = rememberNavController()

NavHost(navController = navController, startDestination = Profile) {
    composable<Profile> { ProfileScreen( /* ... */ ) }
    composable<FriendsList> { FriendsListScreen( /* ... */ ) }
    // Add more destinations similarly.
}
  1. シリアル化可能なオブジェクトは、2 つのルート(ProfileFriendsList)のそれぞれを表します。
  2. NavHost コンポーザブルを呼び出すと、NavController と開始デスティネーションのルート渡されます。
  3. NavHost に渡されたラムダにより、最終的に NavController.createGraph() が呼び出され、NavGraph が返されます。
  4. 各ルートは、生成された NavGraph に目的地を追加する NavGraphBuilder.composable<T>() に型引数として渡されます。
  5. composable に渡されたラムダは、そのデスティネーションに対して NavHost が表示するものです。

ラムダを理解する

NavGraph を作成するラムダについては、前のスニペットで作成したのと同じグラフを作成するためのものと考えると理解しやすいでしょう。NavController.createGraph() を使用して個別に NavGraph を作成し、直接 NavHost に渡すことができます。

val navGraph by remember(navController) {
  navController.createGraph(startDestination = Profile)) {
    composable<Profile> { ProfileScreen( /* ... */ ) }
    composable<FriendsList> { FriendsListScreen( /* ... */ ) }
  }
}
NavHost(navController, navGraph)

引数を渡す

デスティネーションにデータを渡す必要がある場合は、パラメータを持つクラスを使用してルートを定義します。たとえば、Profile ルートは name パラメータを持つデータクラスです。

@Serializable
data class Profile(val name: String)

そのデスティネーションに引数を渡す必要がある場合は、ルートクラスのインスタンスを作成し、引数をクラスのコンストラクタに渡します。

オプションの引数には、デフォルト値を持つ null を許容するフィールドを作成します。

@Serializable
data class Profile(val nickname: String? = null)

ルート インスタンスを取得する

ルート インスタンスは NavBackStackEntry.toRoute() または SavedStateHandle.toRoute() で取得できます。composable() を使用してデスティネーションを作成する場合、NavBackStackEntry をパラメータとして使用できます。

@Serializable
data class Profile(val name: String)

val navController = rememberNavController()

NavHost(navController = navController, startDestination = Profile(name="John Smith")) {
    composable<Profile> { backStackEntry ->
        val profile: Profile = backStackEntry.toRoute()
        ProfileScreen(name = profile.name) }
}

このスニペットの次の点に注意してください。

  • Profile ルートでは、name の引数として "John Smith" を指定して、ナビゲーション グラフの開始地点を指定します。
  • 宛先自体は composable<Profile>{} ブロックです。
  • ProfileScreen コンポーザブルは、独自の name 引数に profile.name の値を受け取ります。
  • そのため、値 "John Smith"ProfileScreen に渡されます。

最も簡単な例

NavControllerNavHost が連携して動作する完全な例を示します。

@Serializable
data class Profile(val name: String)

@Serializable
object FriendsList

// Define the ProfileScreen composable.
@Composable
fun ProfileScreen(
    profile: Profile
    onNavigateToFriendsList: () -> Unit,
  ) {
  Text("Profile for ${profile.name}")
  Button(onClick = { onNavigateToFriendsList() }) {
    Text("Go to Friends List")
  }
}

// Define the FriendsListScreen composable.
@Composable
fun FriendsListScreen(onNavigateToProfile: () -> Unit) {
  Text("Friends List")
  Button(onClick = { onNavigateToProfile() }) {
    Text("Go to Profile")
  }
}

// Define the MyApp composable, including the `NavController` and `NavHost`.
@Composable
fun MyApp() {
  val navController = rememberNavController()
  NavHost(navController, startDestination = Profile(name = "John Smith")) {
    composable<Profile> { backStackEntry ->
        val profile: Profile = backStackEntry.toRoute()
        ProfileScreen(
            profile = profile,
            onNavigateToFriendsList = {
                navController.navigate(route = FriendsList)
            }
        )
    }
    composable<FriendsList> {
      FriendsListScreen(
        onNavigateToProfile = {
          navController.navigate(
            route = Profile(name = "Aisha Devi")
          )
        }
      )
    }
  }
}

このスニペットでは、NavController をコンポーザブルに渡す代わりに、イベントを NavHost に公開しています。この場合、コンポーザブルには、NavHostNavController.navigate() を呼び出すラムダを渡すための () -> Unit 型のパラメータが必要となります。

フラグメント

前のセクションで説明したように、フラグメントを使用すると、Kotlin DSL、XML、または Android Studio エディタを使用して、プログラマティックにナビゲーション グラフを作成できます。

以降のセクションでは、これらの方法について詳しく説明します。

プログラマティック

Kotlin DSL を使用すると、フラグメントによるナビゲーション グラフをプログラマティックに作成できます。XML リソース ファイルを使用する方法に比べ、多くの点でより簡潔で先進的な方法です。

次の例で、2 画面のナビゲーション グラフを実装する場合を考えてみましょう。

まず、NavHostFragment を作成する必要があります。ただし、これには app:navGraph 要素は含めないようにしてください。

<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_fragment"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</FrameLayout>

次に、NavHostFragmentidNavController.findNavController に渡します。これにより、NavController が NavHostFragment に関連付けられます。

続いて NavController.createGraph() を呼び出すと、グラフが NavController にリンクされ、結果として NavHostFragment にもリンクされます。

@Serializable
data class Profile(val name: String)

@Serializable
object FriendsList

// Retrieve the NavController.
val navController = findNavController(R.id.nav_host_fragment)

// Add the graph to the NavController with `createGraph()`.
navController.graph = navController.createGraph(
    startDestination = Profile(name = "John Smith")
) {
    // Associate each destination with one of the route constants.
    fragment<ProfileFragment, Profile> {
        label = "Profile"
    }

    fragment<FriendsListFragment, FriendsList>() {
        label = "Friends List"
    }

    // Add other fragment destinations similarly.
}

この方法での DSL の使用は、前の Compose のセクションで説明したワークフローと非常によく似ています。たとえば、どちらの場合も NavController.createGraph() 関数で NavGraph を生成します。同様に、NavGraphBuilder.composable() はコンポーザブルのデスティネーションをグラフに追加しますが、この場合は NavGraphBuilder.fragment() がフラグメント デスティネーションを追加します。

Kotlin DSL の使用方法については、NavGraphBuilder DSL でグラフを作成するをご覧ください。

XML

XML は自分で直接記述できます。次の例は、前のセクションの 2 画面の例と同等のものです。

まず、NavHostFragment を作成します。これは、実際のナビゲーション グラフを含むナビゲーション ホストとして機能します。

次に、NavHostFragment の最小限の実装を示します。

<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_fragment"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:navGraph="@navigation/nav_graph" />

</FrameLayout>

NavHostFragment には、属性 app:navGraph が含まれています。この属性を使用して、ナビゲーション グラフをナビゲーション ホストに接続します。次に、グラフの実装方法の例を示します。

<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/nav_graph"
    app:startDestination="@id/profile">

    <fragment
        android:id="@+id/profile"
        android:name="com.example.ProfileFragment"
        android:label="Profile">

        <!-- Action to navigate from Profile to Friends List. -->
        <action
            android:id="@+id/action_profile_to_friendslist"
            app:destination="@id/friendslist" />
    </fragment>

    <fragment
        android:id="@+id/friendslist"
        android:name="com.example.FriendsListFragment"
        android:label="Friends List" />

    <!-- Add other fragment destinations similarly. -->
</navigation>

アクションを使用して、個別のデスティネーション間の接続を定義します。この例では、friendslist に移動するアクションが profile フラグメントに含まれています。詳細については、ナビゲーション アクションとフラグメントを使用するをご覧ください。

編集者

アプリのナビゲーション グラフは、Android Studio の Navigation Editor を使用して管理できます。前のセクションでも使用したこのエディタは、NavigationFragment の XML の作成と編集に使用できる GUI です。

詳しくは、Navigation Editor をご覧ください。

ネストされたグラフ

ネストされたグラフを使用することもできます。その場合は、グラフをナビゲーション デスティネーションとして使用します。詳しくは、ネストされたグラフをご覧ください。

関連情報

ナビゲーションの基本的な概念については、以下のガイドをご覧ください。