一般的に、アプリ内のログインフロー、ウィザード、その他のサブフローは、ネストされたナビゲーション グラフとして表現するのが最も適切です。このように自己完結型のサブナビゲーション フローをネストすることにより、アプリの UI のメインフローの把握と管理が容易になります。
また、ネストグラフは再利用可能です。さらに、一定レベルのカプセル化も実現できます。ネストグラフの外部にあるデスティネーションは、ネストグラフの内部にあるデスティネーションに直接アクセスすることができません。代わりに、navigate()
を使用して、ネストグラフ自体にアクセスする必要があります。ネストグラフの内部ロジックは、グラフの残りの部分に影響を与えることなく変更できます。
例
アプリのトップレベル ナビゲーション グラフは、ユーザーがアプリを起動したときに最初に表示される開始デスティネーションから始まり、ユーザーがアプリ内を移動する際に表示されるすべてのデスティネーションを含む必要があります。
図 1 のトップレベル ナビゲーション グラフを例として使用します。 ユーザーに title_screen 画面と register 画面を表示させる場合 アプリが初めて起動されるときだけです。その後、ユーザー情報は 保存されるため、その後のアプリの起動時には、 match 画面に移動します。
match 画面をレスポンスの開始デスティネーションとして設定することをおすすめします。 トップレベル ナビゲーション グラフを作成し、タイトル画面と登録画面をネストする 構成します。
match 画面が開いたら、ユーザーが登録済みかどうかを確認します。条件 ユーザーが登録されていない場合は、ユーザーを登録画面に移動します。
条件付きナビゲーション シナリオの詳細については、条件付きナビゲーションをご覧ください。
Compose
Compose を使用してネストされたナビゲーション グラフを作成するには、NavGraphBuilder.navigation()
関数を使用します。navigation()
の使い方は、グラフにデスティネーションを追加する際の NavGraphBuilder.composable()
関数や NavGraphBuilder.dialog()
関数の使い方と同様です。
主な違いは、navigation
は新しいデスティネーションではなくネストされたグラフを作成することです。次に、composable()
と dialog()
を呼び出します。
ネストされたグラフにデスティネーションを追加する navigation()
のラムダ。
次のスニペットでは、Compose を使用して図 2 のグラフを実装しています。
// Routes
@Serializable object Title
@Serializable object Register
// Route for nested graph
@Serializable object Game
// Routes inside nested graph
@Serializable object Match
@Serializable object InGame
@Serializable object ResultsWinner
@Serializable object GameOver
NavHost(navController, startDestination = Title) {
composable<Title> {
TitleScreen(
onPlayClicked = { navController.navigate(route = Register) },
onLeaderboardsClicked = { /* Navigate to leaderboards */ }
)
}
composable<Register> {
RegisterScreen(
onSignUpComplete = { navController.navigate(route = Game) }
)
}
navigation<Game>(startDestination = Match) {
composable<Match> {
MatchScreen(
onStartGame = { navController.navigate(route = InGame) }
)
}
composable<InGame> {
InGameScreen(
onGameWin = { navController.navigate(route = ResultsWinner) },
onGameLose = { navController.navigate(route = GameOver) }
)
}
composable<ResultsWinner> {
ResultsWinnerScreen(
onNextMatchClicked = {
navController.navigate(route = Match) {
popUpTo(route = Match) { inclusive = true }
}
},
onLeaderboardsClicked = { /* Navigate to leaderboards */ }
)
}
composable<GameOver> {
GameOverScreen(
onTryAgainClicked = {
navController.navigate(route = Match) {
popUpTo(route = Match) { inclusive = true }
}
}
)
}
}
}
ネストされたデスティネーションに直接移動するには、ルートタイプを 宛先に送信されますルートはグローバルなコンセプトであり、 どの画面でも移動できるデスティネーションを特定する:
navController.navigate(route = Match)
XML
XML を使用する場合は、Navigation Editor を使用してネストされたグラフを作成できます。方法は次のとおりです。
- Navigation Editor で、Shift キーを長押ししながら、ネストされたグラフ内に含めるデスティネーションをクリックします。
右クリックしてコンテキスト メニューを開き、[Move to Nested Graph] > [New Graph] を選択します。対象デスティネーションがネストされたグラフ内に囲い込まれます。Navigation Editor 内のネストされたグラフを図 2 に示します。
ネストされたグラフをクリックします。次の属性が [Attributes] パネルに表示されます。
- Type - 「ネストされたグラフ」が格納されます。
- ID - システムによって割り当てられたネストされたグラフの ID が格納されます。この ID は、コードからネストされたグラフを参照するために使用されます。
ネストされたグラフをダブルクリックすると、デスティネーションが表示されます。
[Text] タブをクリックして、XML ビューに切り替えます。ネストされたナビゲーション グラフがグラフに追加されています。このナビゲーション グラフは、独自の
navigation
要素に加えて、独自の ID とstartDestination
属性を備えています。この属性が、ネストされたグラフ内の最初のデスティネーションを指します。<?xml version="1.0" encoding="utf-8"?> <navigation xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" xmlns:android="http://schemas.android.com/apk/res/android" app:startDestination="@id/mainFragment"> <fragment android:id="@+id/mainFragment" android:name="com.example.cashdog.cashdog.MainFragment" android:label="fragment_main" tools:layout="@layout/fragment_main" > <action android:id="@+id/action_mainFragment_to_sendMoneyGraph" app:destination="@id/sendMoneyGraph" /> <action android:id="@+id/action_mainFragment_to_viewBalanceFragment" app:destination="@id/viewBalanceFragment" /> </fragment> <fragment android:id="@+id/viewBalanceFragment" android:name="com.example.cashdog.cashdog.ViewBalanceFragment" android:label="fragment_view_balance" tools:layout="@layout/fragment_view_balance" /> <navigation android:id="@+id/sendMoneyGraph" app:startDestination="@id/chooseRecipient"> <fragment android:id="@+id/chooseRecipient" android:name="com.example.cashdog.cashdog.ChooseRecipient" android:label="fragment_choose_recipient" tools:layout="@layout/fragment_choose_recipient"> <action android:id="@+id/action_chooseRecipient_to_chooseAmountFragment" app:destination="@id/chooseAmountFragment" /> </fragment> <fragment android:id="@+id/chooseAmountFragment" android:name="com.example.cashdog.cashdog.ChooseAmountFragment" android:label="fragment_choose_amount" tools:layout="@layout/fragment_choose_amount" /> </navigation> </navigation>
コード内で、ルートグラフをネストされたグラフに接続するアクションのリソース ID を渡します。
Kotlin
view.findNavController().navigate(R.id.action_mainFragment_to_sendMoneyGraph)
Java
Navigation.findNavController(view).navigate(R.id.action_mainFragment_to_sendMoneyGraph);
- [Design] タブに戻って、[Root] をクリックすると、ルートグラフに戻ることができます。
include を使用して他のナビゲーション グラフを参照する
グラフ構造をモジュール化するもう 1 つの方法は、親ナビゲーション グラフ内の <include>
要素を使用して、別のグラフを子グラフとして組み込むことです。この方法では、組み込まれる側のグラフを独立したモジュールまたはプロジェクト内で定義できるため、最大限の再利用性を実現できます。
次のスニペットは、<include>
の使用方法を示しています。
<!-- (root) nav_graph.xml -->
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/nav_graph"
app:startDestination="@id/fragment">
<strong><include app:graph="@navigation/included_graph" /></strong>
<fragment
android:id="@+id/fragment"
android:name="com.example.myapplication.BlankFragment"
android:label="Fragment in Root Graph"
tools:layout="@layout/fragment_blank">
<strong><action
android:id="@+id/action_fragment_to_second_graph"
app:destination="@id/second_graph" /></strong>
</fragment>
...
</navigation>
<!-- included_graph.xml -->
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
<strong>android:id="@+id/second_graph"</strong>
app:startDestination="@id/includedStart">
<fragment
android:id="@+id/includedStart"
android:name="com.example.myapplication.IncludedStart"
android:label="fragment_included_start"
tools:layout="@layout/fragment_included_start" />
</navigation>
参考情報
ナビゲーションについて詳しくは、以下の参考情報をご覧ください。