ナビゲーション 3

Navigation 3 は、Jetpack Compose 向けにゼロから設計されたナビゲーション ライブラリです。このガイドでは、Wear OS アプリケーションに Navigation 3 を実装する方法について説明します。

基本概念

  • NavKey: アプリ内の宛先(画面)の型安全でシリアル化可能な識別子。
  • NavBackStack: ナビゲーション履歴を表す NavKey インスタンスの可変リスト。このリストから直接アイテムをプッシュおよびポップします。
  • rememberNavBackStack: 構成の変更やプロセスの終了後もバックスタックを作成して保持するコンポーザブル。
  • NavDisplay: バックスタックを監視してアクティブな画面をレンダリングするコア UI コンポーネント。
  • EntryProvider: NavKey を実際の @Composable UI にリンクするマッピング DSL。
  • SwipeDismissableSceneStrategy: 画面をスワイプして閉じる操作でラップし、組み込みの戻るアニメーションを処理する、Wear 固有の戦略。

ステップ 1: 依存関係を追加する

必要な Navigation 3、Wear Compose、シリアル化の依存関係をプロジェクトに追加します。

Groovy

dependencies {
    // Core Navigation 3 APIs
    implementation "androidx.navigation3:navigation3-runtime:1.2.0-alpha02"
    implementation "androidx.navigation3:navigation3-ui:1.2.0-alpha02"

    // Wear OS specific Navigation 3 integration
    implementation "androidx.wear.compose:compose-navigation3:1.6.1"

    // Kotlinx Serialization for type-safe routing
    implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.10.0"
}

Kotlin

dependencies {
    // Core Navigation 3 APIs
    implementation("androidx.navigation3:navigation3-runtime:1.2.0-alpha02")
    implementation("androidx.navigation3:navigation3-ui:1.2.0-alpha02")

    // Wear OS specific Navigation 3 integration
    implementation("androidx.wear.compose:compose-navigation3:1.6.1")

    // Kotlinx Serialization for type-safe routing
    implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.10.0")
}

ステップ 2: 宛先(NavKey)を定義する

画面は、NavKey インターフェースを実装する、厳密に型指定されたシリアル化可能なオブジェクトまたはデータクラスとして定義されます。

@Serializable
sealed interface Screen : NavKey {
    @Serializable
    data object Home : Screen

    @Serializable
    data class Details(val itemId: String) : Screen
}

ステップ 3: NavDisplay とバックスタックを設定する

アプリケーションのルートで、バックスタックと Wear OS シーン戦略を初期化し、それらを NavDisplay に接続します。

// 1. Create the persistent back stack starting at the Home screen
val backStack = rememberNavBackStack(Screen.Home)

// 2. Initialize the Wear OS swipe-to-dismiss strategy
val strategy = rememberSwipeDismissableSceneStrategy<NavKey>()

// 3. Render the NavDisplay
NavDisplay(
    backStack = backStack,
    sceneStrategies = listOf(strategy),
    entryProvider = entryProvider {
        // 4. Map keys to Composables
        entry<Screen.Home> {
            HomeScreen(
                onNavigateToDetails = { id -> backStack.add(Screen.Details(id)) }
            )
        }
        entry<Screen.Details> { key ->
            DetailsScreen(
                itemId = key.itemId,
                onBack = { backStack.removeAt(backStack.lastIndex) }
            )
        }
    }
)

ステップ 4: ナビゲーション アクションを実行する

バックスタックはカスタマイズされた MutableList にすぎないため、ナビゲーションは非常に簡単です。backStack インスタンスで直接オペレーションを実行します。

  • 次の項目に移動: backStack.add(Screen.Details("123"))
  • 戻る: backStack.removeLast() または backStack.removeLastOrNull()
  • クリアとリセット: backStack.clear(); backStack.add(Screen.Home)(または、リスト オペレーションを使用してスタックを置き換えます)。

ステップ 5: (省略可)ViewModel のスコープをデスティネーションに設定する

デフォルトでは、ViewModelActivity にスコープ設定されています。Navigation 3 には、バックスタックの NavEntryViewModel を安全にスコープするための特定のアーティファクト(lifecycle-viewmodel-navigation3)が用意されています。デスティネーションがバックスタックからポップオフされると、ViewModel がクリアされます。

  1. 依存関係を追加します。

    implementation("androidx.lifecycle:lifecycle-viewmodel-navigation3:...")
    
  2. ViewModel ストア デコレータを NavDisplayentryDecorators に追加します。Compose の rememberSaveable 状態を保持するためにカスタム デコレータを指定する場合は、SaveableStateHolderNavEntryDecorator も明示的に含める必要があります。

    NavDisplay(
        backStack = backStack,
        sceneStrategies = listOf(strategy),
        entryDecorators = listOf(
            rememberSaveableStateHolderNavEntryDecorator(),
            rememberViewModelStoreNavEntryDecorator()
        ),
        entryProvider = entryProvider {
            entry<Screen.Home> {
                // Any viewModel() requested here will be scoped to this NavEntry
                val viewModel: HomeViewModel = viewModel()
            }
        }
    )