Comprendere e implementare le nozioni di base

La navigazione descrive il modo in cui gli utenti si spostano nella tua app. Gli utenti interagiscono con gli elementi dell'interfaccia utente, di solito toccandoli o facendoci clic sopra, e l'app risponde mostrando nuovi contenuti. Se l'utente vuole tornare ai contenuti precedenti, usa il gesto Indietro o tocca il pulsante Indietro.

Modellazione dello stato di navigazione

Un modo pratico per modellare questo comportamento è utilizzare una serie di contenuti. Quando l'utente avanza verso nuovi contenuti, questi vengono inseriti in cima alla serie. Quando torna indietro, i contenuti vengono rimossi dall'elenco e vengono visualizzati quelli precedenti. In termini di navigazione, questa serie è in genere indicata come back stack perché rappresenta i contenuti a cui l'utente può tornare.

Un pulsante di azione della tastiera software (un'icona a forma di segno di spunta) cerchiato in rosso.
Figura 1. Diagramma che mostra come la pila di navigazione cambia con gli eventi di navigazione dell'utente.

Creare una pila di ritorno

In Navigazione 3, la pila di navigazione non contiene effettivamente contenuti. Al loro interno sono contenuti riferimenti ai contenuti, noti come chiavi. Le chiavi possono essere di qualsiasi tipo, ma solitamente sono classi di dati semplici e serializzabili. L'utilizzo di riferimenti anziché di contenuti presenta i seguenti vantaggi:

  • È facile navigare premendo i tasti sulla serie di tasti Indietro.
  • Se le chiavi sono serializzabili, la pila di ritorno può essere salvata in un archiviazione permanente, il che consente di sopravvivere alle modifiche alla configurazione e all'interruzione del processo. Questo è importante perché gli utenti si aspettano di uscire dalla tua app, di tornarci più tardi e di riprendere da dove avevano interrotto con gli stessi contenuti visualizzati. Per saperne di più, consulta Salvare la pila Indietro.

Un concetto chiave dell'API Navigation 3 è che sei il proprietario della pila di navigazione a ritroso. La biblioteca:

  • Si prevede che lo stack di ritorno sia un List<T> basato sullo stato snapshot, dove T è il tipo di stack di ritorno keys. Puoi utilizzare Any o fornire le tue chiavi con tipi più forti. Quando vedi i termini "push" o "pop", l'implementazione sottostante consiste nell'aggiungere o rimuovere elementi dalla fine di un elenco.
  • Osserva la pila di ritorno e ne riflette lo stato nell'interfaccia utente utilizzando un NavDisplay.

L'esempio seguente mostra come creare chiavi e una pila di navigazione e modificarla 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 ai contenuti

I contenuti vengono modellati in Navigation 3 utilizzando NavEntry, una classe contenente una funzione componibile. Rappresenta una destinazione, ovvero un singolo contenuto a cui l'utente può andare e tornare.

Un NavEntry può contenere anche metadati, ovvero informazioni sui contenuti. Questi metadati possono essere letti dagli oggetti contenitore, come NavDisplay, per aiutarli a decidere come visualizzare i contenuti di NavEntry. Ad esempio, i metadati possono essere utilizzati per eseguire l'override delle animazioni predefinite per un NavEntry specifico. NavEntrymetadata è una mappa di chiavi String a valori Any, che fornisce un versatile archiviazione dei dati.

Per convertire un key in un NavEntry, crea un entryProvider. Si tratta di una funzione che accetta un key e restituisce un NavEntry per quel key. Generalmente viene definito come parametro lambda durante la creazione di un NavDisplay.

Esistono due modi per creare un entryProvider: creando direttamente una funzione lambda o utilizzando il DSL entryProvider.

Creare direttamente una funzione entryProvider

In genere, crei una funzione entryProvider utilizzando un'istruzione when con un ramo per ogni chiave.

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

Utilizzare il DSL entryProvider

Il DSL entryProvider può semplificare la funzione lambda evitando di dover eseguire il test su ciascun tipo di chiave e di creare un NavEntry per ogni tipo. A tale scopo, utilizza la funzione di compilatore entryProvider. Include anche il comportamento di riserva predefinito (l'emissione 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} ") }
}

Tieni presente quanto segue dallo snippet:

  • entry viene utilizzato per definire un NavEntry con il tipo e i contenuti composable specificati
  • entry accetta un parametro metadata per impostare NavEntry.metadata

Mostra la pila precedente

La pila di navigazione rappresenta lo stato di navigazione dell'app. Ogni volta che la pila di app inferiore cambia, l'interfaccia utente dell'app deve riflettere il nuovo stato della pila di app inferiore. In Navigazione 3, un NavDisplay osserva la pila di ritorno e aggiorna la relativa UI di conseguenza. Costruiscilo con i seguenti parametri:

  • La pila di ritorno, che deve essere di tipo SnapshotStateList<T>, dove T è il tipo di chiavi della pila di ritorno. È un List osservabile, quindi attiva la ricostituzione di NavDisplay quando cambia.
  • Un entryProvider per convertire le chiavi nello stack di ritorno in NavEntry.
  • Se vuoi, specifica una funzione lambda per il parametro onBack. Viene chiamato quando l'utente attiva un evento di ritorno.

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 il NavEntry più in alto nella pila precedente in un layout a riquadro singolo. La registrazione seguente mostra questa app in esecuzione:

Comportamento predefinito di &quot;NavDisplay&quot; con due
destinazioni.
Figura 2. Comportamento predefinito di NavDisplay con due destinazioni.

Riassumendo

Il seguente diagramma mostra il flusso dei dati tra i vari oggetti in Navigation 3:

Una visualizzazione del flusso dei dati tra i vari oggetti in Navigazione 3.
Figura 3. Diagramma che mostra il flusso dei dati attraverso vari oggetti in Navigazione 3.
  1. Gli eventi di navigazione avviano le modifiche. Le chiavi vengono aggiunte o rimosse dalla pila di ritorno in risposta alle interazioni dell'utente.

  2. La modifica dello stato della pila posteriore attiva il recupero dei contenuti. NavDisplay (un composable che esegue il rendering di una pila di app di ritorno) osserva la pila di app di ritorno. Nella configurazione predefinita, mostra la voce della pila di ritorno più in alto in un layout a riquadro singolo. Quando la chiave superiore nella pila posteriore cambia, NavDisplay utilizza questa chiave per richiedere i contenuti corrispondenti al fornitore di voci.

  3. Il fornitore di voci fornisce i contenuti. Il provider di voci è una funzione che risolve una chiave in un NavEntry. Dopo aver ricevuto una chiave dal NavDisplay, il fornitore di voci fornisce il NavEntry associato, che contiene sia la chiave sia i contenuti.

  4. I contenuti vengono visualizzati. NavDisplay riceve NavEntry e visualizza i contenuti.