Navegação 3

A Navigation 3 é uma biblioteca de navegação projetada do zero para o Jetpack Compose. Este guia explica como implementar a Navegação 3 em aplicativos do Wear OS.

Conceitos básicos

  • NavKey: um identificador serializável e com segurança de tipo para um destino (tela) no seu app.
  • NavBackStack: uma lista mutável de instâncias NavKey que representam o histórico de navegação. Você envia e remove itens diretamente dessa lista.
  • rememberNavBackStack: um elemento combinável que cria e mantém a backstack em mudanças de configuração e encerramento do processo.
  • NavDisplay: o componente principal da interface que observa o backstack e renderiza a tela ativa.
  • EntryProvider: uma DSL de mapeamento que vincula um NavKey à interface @Composable real.
  • SwipeDismissableSceneStrategy: a estratégia específica do Wear que envolve suas telas em um gesto de deslizar para dispensar e processa animações de volta integradas.

Etapa 1: adicionar dependências

Adicione as dependências necessárias de navegação 3, Wear Compose e serialização ao projeto.

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")
}

Etapa 2: definir destinos (NavKeys)

As telas são definidas como objetos ou classes de dados serializáveis e fortemente tipados que implementam a interface NavKey.

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

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

Etapa 3: configurar NavDisplay e o backstack

Na raiz do aplicativo, inicialize o backstack e a estratégia de cena do Wear OS e conecte-as ao 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) }
            )
        }
    }
)

Etapa 4: realizar ações de navegação

Como a backstack é apenas um MutableList personalizado, a navegação é muito simples. Você realiza operações diretamente na instância backStack:

  • Navegar para frente: backStack.add(Screen.Details("123"))
  • Voltar: backStack.removeLast() ou backStack.removeLastOrNull()
  • Limpar e redefinir: backStack.clear(); backStack.add(Screen.Home) (ou use operações de lista para substituir a pilha).

Etapa 5: (opcional) definir o escopo das ViewModels para destinos

Por padrão, os ViewModels são definidos como Activity. A navegação 3 fornece um artefato específico (lifecycle-viewmodel-navigation3) para escopo seguro de um ViewModel para um NavEntry na backstack. Quando o destino é retirado da backstack, o ViewModel é apagado.

  1. Adicione a dependência:

    implementation("androidx.lifecycle:lifecycle-viewmodel-navigation3:...")
    
  2. Adicione o decorador de armazenamento do ViewModel ao entryDecorators do NavDisplay. Você também precisa incluir explicitamente o SaveableStateHolderNavEntryDecorator ao fornecer decoradores personalizados para reter o estado rememberSaveable do Compose:

    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()
            }
        }
    )