Navigation3

new-silvermoon/awesome-android-agent-skills/.github/skills/ui/compose-navigation

作者 new-silvermoon82900eacc8dbe13de93c6310af27b9df4b2bd2f6無授權條款收錄於 2026年10月9日更新於 2026年10月9日

Implement navigation in Jetpack Compose using Navigation 3. Use when asked to build state-driven navigation, manage back stacks, scope ViewModels, implement adaptive layouts, or migrate from Navigation Compose.

AI 產生的概覽

指導使用 Android Navigation 3 在 Jetpack Compose 中實作狀態驅動導覽。

功能
此技能提供在 Jetpack Compose 中使用 Navigation 3 建構導覽的參考指引,核心是把導覽建模為可觀察的應用程式狀態,而非使用 NavController。內容涵蓋定義可序列化的導覽鍵、管理可變返回堆疊、設定 NavDisplay、透過項目裝飾器限定 ViewModel 範圍、自適應版面、深層連結、動畫、狀態還原與測試。它也包含從 Navigation Compose 遷移至 Navigation 3 的對照表以及建議的專案結構。
適用情境
適用於使用 Navigation 3 建構或重構 Android Jetpack Compose 導覽的情境,包括狀態驅動導覽、返回堆疊處理、ViewModel 範圍、自適應版面,或從 Navigation Compose 遷移。也適用於此技術堆疊中的深層連結、轉場、狀態還原與導覽測試。
執行需求
需要採用 Navigation 3 的 Android Jetpack Compose 專案,相依項目包括 androidx.navigation3 執行階段與 UI、生命週期 ViewModel 整合及 kotlinx-serialization,並啟用 Kotlin 序列化外掛。此技能不附帶指令碼,僅為說明文件。

Navigation 3

Overview

Implement state-driven navigation in Jetpack Compose using Navigation 3. Unlike Navigation Compose, Navigation 3 models navigation as application state rather than through a NavController. This skill covers navigation keys, back stack management, ViewModel scoping, entry decorators, adaptive layouts, deep links, animations, state restoration, and testing.

Setup

Add the Navigation 3 dependencies:

kotlin
// build.gradle.ktsdependencies {
    implementation("androidx.navigation3:navigation3-runtime:1.0.0-alpha08")    implementation("androidx.navigation3:navigation3-ui:1.0.0-alpha08")
    // Lifecycle integration    implementation("androidx.lifecycle:lifecycle-viewmodel-navigation3:2.9.2")
    // Serialization    implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.8.1")}
// Enable serialization pluginplugins {    kotlin("plugin.serialization") version "2.2.0"}

Core Concepts

1. Define Navigation Keys

Navigation destinations are represented by immutable serializable objects.

kotlin
import kotlinx.serialization.Serializable
@Serializabledata object Home
@Serializabledata class Profile(    val userId: String)
@Serializabledata class Product(    val productId: String,    val showReviews: Boolean = false)
@Serializabledata object Settings

Keys become your navigation state.


2. Create the Back Stack

Navigation 3 replaces NavController with a mutable state back stack.

kotlin
@Composablefun MyApp() {
    val backStack = remember {        mutableStateListOf<Any>(Home)    }
    AppNavDisplay(backStack)}

3. Create NavDisplay

kotlin
@Composablefun AppNavDisplay(    backStack: SnapshotStateList<Any>) {
    NavDisplay(        backStack = backStack,        onBack = {            if (backStack.size > 1) {                backStack.removeLast()            }        }    ) { key ->
        when (key) {
            Home ->                HomeScreen(                    onProfileClick = {                        backStack += Profile(it)                    }                )
            is Profile ->                ProfileScreen(                    userId = key.userId                )
            is Product ->                ProductScreen(                    productId = key.productId,                    showReviews = key.showReviews                )
            Settings ->                SettingsScreen()        }    }}

Navigation Patterns

Navigate Forward

kotlin
backStack += Profile("user123")

Navigate Back

kotlin
backStack.removeLast()

Replace Current Screen

kotlin
backStack[backStack.lastIndex] = Home

Clear Back Stack

kotlin
backStack.clear()backStack += Home

Pop To Root

kotlin
while (backStack.size > 1) {    backStack.removeLast()}

Argument Handling

Retrieve Arguments

Arguments already exist inside the navigation key.

kotlin
when (val key = currentKey) {
    is Profile -> {        ProfileScreen(            userId = key.userId        )    }
    is Product -> {        ProductScreen(            productId = key.productId        )    }}

Pass IDs, Not Objects

kotlin
// CORRECTbackStack += Profile(user.id)
// Fetch object inside ViewModelclass ProfileViewModel(    savedStateHandle: SavedStateHandle,    repository: UserRepository) : ViewModel() {
    val profile = savedStateHandle.toRoute<Profile>()
    val user =        repository.getUser(profile.userId)}
kotlin
// INCORRECT
backStack += User(...)backStack += ProductRepository(...)backStack += ProductViewModel(...)

ViewModel Integration

Navigation 3 scopes ViewModels using entry decorators.

kotlin
NavDisplay(
    backStack = backStack,
    entryDecorators = listOf(
        rememberSceneSetupNavEntryDecorator(),
        rememberSavedStateNavEntryDecorator(),
        rememberViewModelStoreNavEntryDecorator()    )
) { key ->
    // destinations}

ViewModel Example

kotlin
class ProfileViewModel(    savedStateHandle: SavedStateHandle) : ViewModel() {
    val profile =        savedStateHandle.toRoute<Profile>()}

Entry Decorators

Navigation 3 uses decorators to attach lifecycle functionality.

Scene Setup

kotlin
rememberSceneSetupNavEntryDecorator()

Creates the navigation scene for each entry.

Saved State

kotlin
rememberSavedStateNavEntryDecorator()

Automatically restores destination state after process recreation.

ViewModel Store

kotlin
rememberViewModelStoreNavEntryDecorator()

Scopes ViewModels to each navigation entry.


Adaptive Navigation

Navigation 3 integrates with Material Adaptive layouts.

kotlin
NavDisplay(
    backStack = backStack,
    sceneStrategy = rememberListDetailSceneStrategy()
)

Use adaptive scene strategies to automatically switch between:

  • Single pane (phones)
  • Two pane (tablets)
  • Foldables

Deep Links

Deep links should resolve into navigation keys.

kotlin
fun handleDeepLink(uri: Uri) {
    val userId =        uri.lastPathSegment ?: return
    backStack += Profile(userId)}

Avoid manually constructing route strings.


Animations

Navigation transitions are defined using scene transitions.

kotlin
NavDisplay(
    backStack = backStack,
    transitionSpec = {
        fadeIn() togetherWith fadeOut()
    })

Navigation 3 animation APIs may evolve while in alpha.


State Restoration

Navigation keys are serializable and automatically restored.

kotlin
val backStack = rememberSaveable(    saver = navBackStackSaver()) {    mutableStateListOf(Home)}

Always ensure keys are serializable.


Testing

Navigation becomes simple because it is state-driven.

Example

kotlin
@Testfun navigateToProfile() {
    val backStack =        mutableStateListOf<Any>(Home)
    backStack += Profile("123")
    assertEquals(        Profile("123"),        backStack.last()    )}

Compose UI tests can verify screen rendering by inspecting the current back stack.


Migration from Navigation Compose

Navigation ComposeNavigation 3
NavControllerMutable back stack
NavHostNavDisplay
navigate()backStack += Key
popBackStack()removeLast()
String routesSerializable keys
composable()when(key)
Navigation graphState-driven destinations

Recommended Project Structure

navigation/
    AppNavigation.kt
    NavigationKeys.kt
    NavigationDisplay.kt
feature/
    home/
    profile/
    settings/

Critical Rules

DO

  • Use immutable serializable keys
  • Keep navigation state inside Compose
  • Pass IDs instead of complex objects
  • Scope ViewModels using entry decorators
  • Use rememberSaveable for state restoration
  • Model navigation as observable application state

DON'T

  • Use string routes
  • Pass repositories or ViewModels through navigation
  • Mutate navigation keys
  • Store business objects in the back stack
  • Recreate the back stack on recomposition
  • Mix Navigation Compose APIs with Navigation 3 APIs

References

  • Android Navigation 3 documentation
  • Navigation 3 samples
  • Lifecycle ViewModel Navigation 3 documentation
  • Material 3 Adaptive Navigation documentation

來源與署名

來源:new-silvermoon/awesome-android-agent-skills位於.github/skills/ui/compose-navigation提交82900ea

授權條款: 無授權條款

內容歸原作者所有。SourceWeft 從公開儲存庫中收錄這些內容。

檢舉或申請下架