NavHost — Jetpack Composeにおけるナビゲーショングラフとルートの構築

著者: IT Sectr 公開日: 2026-06-30 読了時間: 7 分

NavHostは、Jetpack Composeのナビゲーショングラフのエントリポイントとして機能するcomposableコンテナです。NavControllerを一連のルートにリンクし、バックスタックの状態に基づいて現在の画面をレンダリングします。Android Developers(2025)によると、NavHostはナビゲーションを備えたComposeアプリケーションに必須のコンポーネントです。NavHost内では、オプションの引数、ディープリンク、アニメーションとともにcomposableルートが登録されます。各ルートは、遷移データを持つNavBackStackEntryを受け取る通常のcomposable関数です。NavHostは、バックプレス、状態の保存、再構成時の復元を自動的に処理します。

重要なポイント

  • NavHost — NavControllerをルートグラフにリンクし、現在の画面をレンダリングするcomposableコンテナ
  • composable() — ルート、引数、ディープリンク、遷移アニメーションを持つルートを登録する関数
  • startDestination — NavHost作成時に開かれる初期ルート
  • 引数は、画面間の型付きデータ転送のためにnavArgumentとNavTypeを介して定義されます
  • アニメーションは、enterTransition、exitTransitionパラメータを通じてグローバルまたは個別に設定されます

Jetpack ComposeにおけるNavHostとは?

NavHostは、現在のナビゲーション画面を表示するためのコンテナを提供するcomposable関数です。NavHostは、NavController、startDestination、およびKotlin DSLで構築されたルートグラフを受け取ります。現在のルートが変更されると、NavHostは指定されたアニメーションで表示されるcomposableを切り替えます。

NavHostは画面スイッチャーとして機能します。NavControllerから現在のNavBackStackEntryを追跡し、対応するcomposableブロックをレンダリングします。各画面は独立したcomposable関数であり、ルート引数を持つNavBackStackEntryを受け取ります。すべての画面は単一のコンポジションツリーに存在しますが、NavHostは一度に1つだけを表示し、他の画面はアニメーションで非表示にします。

FragmentManagerとは異なり、NavHostは画面ごとにFragmentを作成しません。ライフサイクル全体はCompositionLifecycleを介して管理されます。composable関数にはonStart/onResumeがないため、副作用にはLaunchedEffectとDisposableEffectが使用されます。NavHostは自動的にNavControllerを購読し、ルートが変更されるとUIを再コンポーズします。

Googleによると、NavHostはNavigation 2.4.0以降の安定したAPIです。2.8.0以降、NavHostはKotlin Serializationを介したタイプセーフナビゲーションをサポートし、文字列ルートをデータクラスに置き換えます。NavHostはネストされたグラフもサポートしており、モジュールベースのナビゲーション編成を可能にします。

NavHostは2つの必須パラメータで作成されます。navController(NavHostControllerのインスタンス)とstartDestination(最初の画面のルート文字列)です。3番目のパラメータは、composable()、navigation()、dialog()を介してすべてのルートが登録されるビルダーブロックです。

kotlin
@Composable
fun AppNavHost(navController: NavHostController) {
    NavHost(
        navController = navController,
        startDestination = "home"
    ) {
        composable("home") { HomeScreen(navController) }
        composable("settings") { SettingsScreen(navController) }
    }
}

startDestinationは、NavHostが最初に起動されたときに開くルートです。バックスタックが空の場合、NavHostは自動的にstartDestinationをスタックに追加します。再構成(画面回転)時、NavHostはsavedStateから最後のルートを復元し、startDestinationは復元しません。

BottomNavigationの場合、startDestinationは下部パネルのルートの1つです。残りのパネルルートは個別のcomposableエントリとして追加されます。NavHostはScaffold.content内に配置する必要があります。ここにメインのアプリケーションコンテンツが表示されます。NavHostは、TopAppBarとBottomNavigationを除いた利用可能な高さをすべて占有します。

composableによるルートの登録

composable(route, arguments, deepLinks, enterTransition, exitTransition, content)関数は、NavHostグラフにルートを登録します。routeパラメータは、{paramName}形式のオプションのプレースホルダーを持つパスを記述する文字列です。ナビゲーション中にプレースホルダーは実際の値に置き換えられます。

composableのcontentブロックは、引数が抽出されるNavBackStackEntryを受け取ります。画面のcomposable関数は、現在のNavControllerルートがルートと一致する場合にのみレンダリングされます。一致しない場合、composableはコンポジションから削除されますが、その状態はrememberSaveableまたはSavedStateHandle付きのViewModelを介して保存できます。

kotlin
composable(
    route = "article/{articleId}",
    arguments = listOf(navArgument("articleId") {
        type = NavType.IntType
        defaultValue = 0
    }),
    deepLinks = listOf(navDeepLink { uriPattern = "https://app.example/article/{articleId}" })
) { backStackEntry ->
    val articleId = backStackEntry.arguments?.getInt("articleId") ?: 0
    ArticleScreen(articleId = articleId)
}

NavHost内のcomposableエントリの数は、数個から数百個までさまざまです。大規模なアプリケーションの場合、ルートはモジュール間で分割され、ネストされたグラフを介して接続されます。各composableは、独自のアニメーション設定、ディープリンク、引数を持つことができます。

引数と型付きルートパラメータ

ルート引数は、composable()のarguments: List<NamedNavArgument>パラメータを介して定義されます。各引数は、navArgument(name) { type; defaultValue }を介して定義されます。NavTypeは引数の型を決定します:StringType、IntType、LongType、FloatType、BoolType、ParcelableType、ReferenceType。

ルートパラメータルートの例NavType
パス(path)"user/{id}"NavType.IntType
クエリ(query)"search?q={query}"NavType.StringType
オプション"details/{id}?tab={tab}"StringType + defaultValue=""
Parcelable"checkout/{order}"NavType.ParcelableType

引数は、arguments?.getInt("id")を介してNavBackStackEntryから抽出されます。必須引数の場合、defaultValueは省略できます。NavTypeはnullを使用します。オプション引数の場合、defaultValueを設定する必要があります。そうしないと、パラメータが欠落している場合にナビゲーションが例外をスローします。

Navigation 2.8.0以降、タイプセーフナビゲーションが推奨されています。Kotlin Serializationを使用して、ルートのシールドクラスまたはデータクラスを定義します。文字列ルートの代わりに、composable<RouteType> { backStackEntry -> }を使用します。これにより、ルートのタイプミスがなくなり、引数のNavTypeが自動的に生成されます。移行するには、navigation-compose-typesafe依存関係とKotlin Serializationプラグインを追加します。

ネストされたナビゲーショングラフ

nested graphsnavigation(route, startDestination)関数を使用してNavHost内でルートをグループ化するメカニズム。ネストされたグラフには独自のルートプレフィックスとstartDestinationがあり、そのすべてのルートはプレフィックスを介してアクセスできます。ネストされたグラフはモジュラーアーキテクチャに使用され、各フィーチャーモジュールが独自のサブグラフを登録します。

ネストされたグラフの利点:モジュール内のルートの分離、画面グループの統一されたバックスタック、内部構造を公開せずにプレフィックスでナビゲートする機能。たとえば、「auth」グラフには「auth/login」と「auth/register」が含まれます。ナビゲーションは、完全なルート、またはstartDestinationへのリダイレクト付きのプレフィックスのいずれかで可能です。

kotlin
NavHost(navController = navController, startDestination = "main") {
    composable("main") { MainScreen(navController) }
    navigation(
        route = "auth",
        startDestination = "auth/login"
    ) {
        composable("auth/login") { LoginScreen(navController) }
        composable("auth/register") { RegisterScreen(navController) }
    }
}

ネストされたグラフは、グラフレベルでの引数渡しをサポートします。グラフのルートで宣言されたパラメータは、すべての内部ルートに渡されます。ネストされたグラフをクリアするには、popBackStack(route)を使用します。これにより、すべての内部エントリが削除されます。ネストされたグラフに深さの制限はありませんが、読みやすさのために3レベル以内が推奨されます。

アニメーションと遷移のカスタマイズ

NavHostは、enterTransitionexitTransitionpopEnterTransitionpopExitTransitionパラメータを介してcomposableルート間の遷移アニメーションをサポートします。アニメーションは一度NavHostに設定され、すべてのルートに適用されるか、各composableに個別に適用されます。デフォルトでは、アニメーションは無効です。

一般的な設定:enterTransition = slideInHorizontally(initialOffsetX = { it }) — 画面が右からスライドインします。exitTransition = slideOutHorizontally(targetOffsetX = { -it }) — 画面が左にスライドアウトします。ポップアニメーションの場合、方向が反転します。画面は左からスライドインし、右にスライドアウトします。BottomNavigationの場合は、スライドなしでfadeIn/fadeOutが使用されます。

kotlin
NavHost(
    navController = navController,
    startDestination = "home",
    enterTransition = { slideInHorizontally(initialOffsetX = { it }) + fadeIn() },
    exitTransition = { slideOutHorizontally(targetOffsetX = { -it }) + fadeOut() },
    popEnterTransition = { slideInHorizontally(initialOffsetX = { -it }) + fadeIn() },
    popExitTransition = { slideOutHorizontally(targetOffsetX = { it }) + fadeOut() }
) { /* composable routes */ }

カスタムアニメーションはCompose Animation APIを使用して作成されます。AnimatedContentTransitionScopeは、コンテナの寸法、アニメーションの進行状況、方向へのアクセスを提供します。共有要素遷移(1つの要素が別の画面にスムーズに移動する)には、Accompanist Navigation Animationライブラリ、またはsharedElement Modifierを介したカスタム実装が必要です。Android Developers(2025)によると、デフォルトのスライドアニメーション(右から入り、左に出る)は、ナビゲーションを備えたAndroidアプリの80%で使用されています。

よくある質問

1つのActivityで複数のNavHostを使用できますか?

技術的には可能ですが、推奨されません。各NavHostは独立したバックスタックを作成し、統一されたナビゲーションを壊します。例外は、メインコンテンツ用のNavHostと、独自のナビゲーションを持つBottomSheet用のNavHostなど、分離された領域です。

ComposeにおけるNavHostとScaffoldの違いは何ですか?

NavHostは画面を切り替えるナビゲーションコンテナです。Scaffoldはページ全体のレイアウト(TopAppBar、BottomNavigation、FloatingActionButton)です。通常、NavHostはScaffold.content内に配置されます。Scaffoldはナビゲーションを管理せず、UIコンポーネントのスロットを提供するだけです。

NavHostを介して画面間でViewModelを共有するには?

ViewModelはNavBackStackEntry内でviewModel()を介して作成されます。画面間でViewModelを共有するには、parentNavControllerを使用します。共有ViewModelを親エントリにバインドします。代替手段は、NavGraphスコープを持つDI(Hilt/Koin)です。

なぜNavHostは遷移のたびにcomposableを再作成するのですか?

これは通常の動作です。ルートを離れる際に、NavHostはcomposableをコンポジションから削除します。状態を保持するには、UI状態にはrememberSaveableを、ビジネスロジックにはSavedStateHandle付きのViewModelを使用します。

NavHostで404(不明なルート)処理を追加するには?

最後のルートとしてcomposable("404")を追加し、不明なディープリンクを受信したときにそこにナビゲートします。NavHostにはキャッチオールルートがありません。navigate()の前に、ディープリンクのインテントハンドラでルートを確認します。ルートが見つからない場合は、404にナビゲートします。

まとめ

  • NavHost — NavControllerをルートグラフにリンクし、現在の画面をレンダリングするNavigation Composeのcomposableコンテナ
  • composable()は、ルート、引数(NavType)、ディープリンク、アニメーションでルートを登録します
  • startDestination — NavHostが最初に起動されたときに開かれる初期ルート
  • 引数は、型付けのためのNavTypeとオプションパラメータのdefaultValueを持つ{param}プレースホルダーを介して渡されます
  • ネストされたグラフは、navigation()を介して、分離されたバックスタックを持つモジュールごとにルートをグループ化できます
  • 遷移のアニメーションは、Compose Animation APIを使用してenterTransition/exitTransitionを介して設定されます
  • NavHostは、追加コードなしでバックプレス、状態保存、ディープリンクを自動的に処理します

ターンキー方式のモバイルアプリケーションを開発します

IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。

プロジェクトについて相談

こちらもお読みください