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 从公开仓库中收录这些内容。

举报或申请下架