La navigazione descrive il modo in cui gli utenti si spostano all'interno della tua app. Gli utenti interagiscono con gli elementi UI, di solito toccandoli o facendoci clic sopra, e l'app risponde mostrando nuovi contenuti. Se l'utente vuole tornare ai contenuti precedenti, utilizza il gesto Indietro o tocca il pulsante Indietro.
Modellazione dello stato di navigazione
Un modo pratico per modellare questo comportamento è utilizzare uno stack di contenuti. Man mano che l'utente naviga in avanti verso nuovi contenuti, questi vengono inseriti in cima allo stack. Quando l'utente torna indietro da questi contenuti, questi vengono rimossi dallo stack e vengono visualizzati i contenuti precedenti. In termini di navigazione, questo stack viene solitamente chiamato back stack perché rappresenta i contenuti a cui l'utente può tornare.
Crea un back stack
In Navigation 3, il back stack non contiene effettivamente contenuti. Contiene invece riferimenti ai contenuti, noti come chiavi. Le chiavi possono essere di qualsiasi tipo, ma di solito sono classi di dati semplici e serializzabili. L'utilizzo di riferimenti anziché di contenuti presenta i seguenti vantaggi:
- È semplice navigare inserendo le chiavi nel back stack.
- Se le chiavi sono serializzabili, il back stack può essere salvato nello spazio di archiviazione permanente, in modo da sopravvivere alle modifiche alla configurazione e all'interruzione del processo. Questo è importante perché gli utenti si aspettano di uscire dall'app, tornare in un secondo momento e riprendere da dove avevano interrotto, con gli stessi contenuti visualizzati. Per saperne di più, consulta Salva il back stack.
Un concetto chiave dell'API Navigation 3 è che il back stack è di tua proprietà. La libreria:
- Si aspetta che il tuo back stack sia un
List<T>supportato dallo stato dello snapshot, doveTè il tipo dikeysdel tuo back stack. Puoi utilizzareAnyo fornire le tue chiavi con un tipo più sicuro. Quando vedi i termini "push" o "pop", l'implementazione sottostante consiste nell'aggiungere o rimuovere elementi dalla fine di un elenco. - Osserva il back stack e ne riflette lo stato nell'interfaccia utente utilizzando un
NavDisplay.
L'esempio seguente mostra come creare chiavi e un back stack e come modificare il back stack in risposta agli eventi di navigazione dell'utente:
// Define keys that will identify content data object ProductList data class ProductDetail(val id: String) @Composable fun MyApp() { // Create a back stack, specifying the key the app should start with val backStack = remember { mutableStateListOf<Any>(ProductList) } // Supply your back stack to a NavDisplay so it can reflect changes in the UI // ...more on this below... // Push a key onto the back stack (navigate forward), the navigation library will reflect the change in state backStack.add(ProductDetail(id = "ABC")) // Pop a key off the back stack (navigate back), the navigation library will reflect the change in state backStack.removeLastOrNull() }
Risolvere le chiavi per i contenuti
I contenuti vengono modellati in Navigation 3 utilizzando NavEntry, una classe contenente una funzione componibile. Rappresenta una destinazione, ovvero un singolo contenuto verso cui l'utente può navigare in avanti e indietro.
Un NavEntry può anche contenere metadati, ovvero informazioni sui contenuti. Questi metadati possono essere letti da oggetti contenitore, come NavDisplay, per aiutarli a decidere come visualizzare i contenuti di NavEntry. Ad esempio, i metadati possono essere utilizzati per sostituire le animazioni predefinite per un NavEntry specifico. NavEntry
metadata è una mappa di chiavi String per i valori Any, che fornisce un'archiviazione dei dati versatile.
Per convertire un key in un NavEntry, crea un Entry Provider. Si tratta di una funzione che accetta un key e restituisce un NavEntry per quel key. In genere viene definito come parametro lambda durante la creazione di un NavDisplay.
Esistono due modi per creare un Entry Provider: creando direttamente una funzione lambda o utilizzando il DSL entryProvider.
Crea direttamente una funzione Entry Provider
In genere, crei una funzione Entry Provider utilizzando un'istruzione when, con un ramo per ciascuna delle tue chiavi.
entryProvider = { key -> when (key) { is ProductList -> NavEntry(key) { Text("Product List") } is ProductDetail -> NavEntry( key, metadata = mapOf("extraDataKey" to "extraDataValue") ) { Text("Product ${key.id} ") } else -> { NavEntry(Unit) { Text(text = "Invalid Key: $it") } } } }
Utilizza il DSL entryProvider
Il DSL entryProvider può semplificare la funzione lambda evitando la necessità di eseguire test su ciascuno dei tipi di chiave e di creare un NavEntry per ciascuno.
Per farlo, utilizza la funzione builder entryProvider. Include anche il comportamento di riserva predefinito (generazione di un errore) se la chiave non viene trovata.
entryProvider = entryProvider { entry<ProductList> { Text("Product List") } entry<ProductDetail>( metadata = mapOf("extraDataKey" to "extraDataValue") ) { key -> Text("Product ${key.id} ") } }
Nello snippet, tieni presente quanto segue:
entryviene utilizzato per definire unNavEntrycon il tipo e i contenuti componibili specificatientryaccetta un parametrometadataper impostareNavEntry.metadata
Visualizza il back stack
Il back stack rappresenta lo stato di navigazione della tua app. Ogni volta che il back stack cambia, la UI dell'app deve riflettere il nuovo stato del back stack. In Navigation 3, un NavDisplay osserva il back stack e aggiorna la UI di conseguenza. Crealo con i seguenti parametri:
- Il tuo back stack: deve essere di tipo
SnapshotStateList<T>, doveTè il tipo delle chiavi del back stack. È unListosservabile, quindi attiva la ricomposizione diNavDisplayquando cambia. - Un
entryProviderper convertire le chiavi nel back stack in oggettiNavEntry. - Facoltativamente, fornisci una funzione lambda al parametro
onBack. Questo metodo viene chiamato quando l'utente attiva un evento Indietro.
L'esempio seguente mostra come creare un NavDisplay.
data object Home data class Product(val id: String) @Composable fun NavExample() { val backStack = remember { mutableStateListOf<Any>(Home) } NavDisplay( backStack = backStack, onBack = { backStack.removeLastOrNull() }, entryProvider = { key -> when (key) { is Home -> NavEntry(key) { ContentGreen("Welcome to Nav3") { Button(onClick = { backStack.add(Product("123")) }) { Text("Click to navigate") } } } is Product -> NavEntry(key) { ContentBlue("Product ${key.id} ") } else -> NavEntry(Unit) { Text("Unknown route") } } } ) }
Per impostazione predefinita, NavDisplay mostra l'elemento NavEntry più in alto nel back stack in un layout a riquadro singolo. La seguente registrazione mostra l'app in esecuzione:
NavDisplay con due destinazioni.Ciclo di vita della destinazione
NavDisplay utilizza LifecycleOwner personalizzati per limitare lo stato del ciclo di vita di un NavEntry in base ai vincoli a livello di scena e di voce.
Per ulteriori informazioni sui cicli di vita in Compose, consulta Ciclo di vita in Jetpack Compose.
Vincoli del ciclo di vita a livello di scena
NavDisplay gestisce il ciclo di vita dei Scene attivi. I limiti a livello di scena vengono determinati come segue:
Per le scene non in overlay:
RESUMED: consentito solo quando la transizione della scena è terminata e non sono presenti scene in overlay attive visualizzate sopra.STARTED: limitato aSTARTEDdurante le transizioni della scena, ad esempio quando si naviga avanti o indietro o quando è coperto da un overlay.
Per le scene in overlay, come le finestre di dialogo o i riquadri inferiori:
RESUMED: consentito solo per la scena in overlay più in alto, attualmente attiva.STARTED: limitato aSTARTEDper tutte le scene di overlay sottostanti coperte da un overlay più recente.
Stato del ciclo di vita di livello base
La libreria gestisce lo stato massimo del ciclo di vita di ogni singola NavEntry
in base alla sua presenza nel back stack:
RESUMED: se la voce è presente nel back stack corrente, il suo ciclo di vita può arrivare fino aRESUMED(soggetto al limite a livello di scena).CREATED: se la voce non è più nel back stack, ad esempio quando è stata rimossa, ma viene ancora visualizzata sullo schermo durante l'animazione, la libreria limita rigorosamente il suo ciclo di vita aCREATED. Questo limite garantisce che le voci in background o in uscita interrompano l'esecuzione di attività attive, come la raccolta di flussi o l'avvio di coroutine associate agli statiRESUMEDoSTARTED, mentre completano le transizioni di uscita.
Come si combinano
Ad esempio, lo stato finale del ciclo di vita di un NavEntry viene risolto come segue:
| Scenario | Limite a livello di scena | Cappello Entry-Level | Limite effettivo |
|---|---|---|---|
| Voce attiva, schermata fissa (senza transizioni o overlay) | RESUMED |
RESUMED |
RESUMED |
| Voce attiva, durante la transizione (navigazione verso o da) | STARTED |
RESUMED |
STARTED |
| Voce attiva, coperta da un overlay (ad esempio, una finestra di dialogo è aperta) | STARTED |
RESUMED |
STARTED |
| Voce estratta, animazione in uscita | STARTED o RESUMED |
CREATED |
CREATED |
Elaborazione della risposta…
Il seguente diagramma mostra il flusso di dati tra i vari oggetti in Navigation 3:
Gli eventi di navigazione avviano le modifiche. Le chiavi vengono aggiunte o rimosse dal back stack in risposta alle interazioni dell'utente.
La modifica dello stato del back stack attiva il recupero dei contenuti.
NavDisplay(un composable che esegue il rendering di un back stack) osserva il back stack. Nella sua configurazione predefinita, mostra la voce del back stack più in alto in un layout a riquadro singolo. Quando la chiave in cima al back stack cambia,NavDisplayla utilizza per richiedere i contenuti corrispondenti al provider di voci.Il fornitore di contenuti fornisce i contenuti. Il provider di voci è una funzione che risolve una chiave in un
NavEntry. Quando riceve una chiave daNavDisplay, il provider di voci fornisce l'oggettoNavEntryassociato, che contiene sia la chiave sia i contenuti.I contenuti vengono visualizzati.
NavDisplayriceveNavEntrye visualizza i contenuti.