Comprendere e implementare le nozioni di base

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

Stato di navigazione della modellazione

Un modo pratico per modellare questo comportamento è con una pila di contenuti. Man mano che l'utente avanza verso nuovi contenuti, questi vengono spostati in cima alla pila. Quando tornano indietro da questi contenuti, questi vengono rimossi dalla pila e vengono visualizzati i contenuti precedenti. In termini di navigazione, questo stack viene solitamente chiamato stack indietro 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 cambia lo stack precedente con gli eventi di navigazione dell'utente.

Creare uno stack indietro

In Navigazione 3, lo stack precedente non contiene 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:

  • È facile da navigare premendo i tasti sulla pila posteriore.
  • Se le chiavi sono serializzabili, lo stack indietro può essere salvato nello spazio di archiviazione permanente, consentendo di sopravvivere alle modifiche alla configurazione e all'interruzione del processo. Questo è importante perché gli utenti si aspettano di uscire dalla tua app, tornarci in un secondo momento e riprendere da dove avevano interrotto la visualizzazione degli stessi contenuti. Per saperne di più, consulta Salvare lo stack di attività.

Un concetto chiave dell'API Navigation 3 è che lo sviluppatore è proprietario dello stack precedente. La biblioteca:

  • Prevede che lo stack precedente sia un List<T> supportato dallo stato dello snapshot, dove T è il tipo di stack precedente keys. Puoi utilizzare Any o fornire chiavi più fortemente tipizzate. Quando vedi i termini "push" o "pop", l'implementazione sottostante consiste nell'aggiungere o rimuovere elementi dalla fine di un elenco.
  • Osserva lo stack precedente e riflette il suo stato nell'UI utilizzando un NavDisplay.

L'esempio seguente mostra come creare chiavi e uno stack indietro e modificare lo stack indietro 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 i problemi relativi alle chiavi dei 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ò avanzare e tornare indietro.

Un NavEntry può contenere anche 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 ignorare le animazioni predefinite per un NavEntry specifico. NavEntry metadata è una mappa di chiavi String e valori Any, che fornisce un versatile archivio di dati.

Per convertire un key in un NavEntry, crea un fornitore di voci. Questa è una funzione che accetta un key e restituisce un NavEntry per quel key. Viene in genere definito come parametro lambda durante la creazione di un NavDisplay.

Esistono due modi per creare un fornitore di voci: creando direttamente una funzione Lambda o utilizzando il linguaggio specifico del dominio (DSL) entryProvider.

Crea direttamente una funzione del fornitore di voci

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 linguaggio specifico del dominio entryProvider

Il entryProvider DSL può semplificare la tua funzione lambda evitando la necessità di eseguire test su ciascun tipo di chiave e di creare un NavEntry per ognuno. A questo scopo, utilizza la funzione di creazione entryProvider. Include anche il comportamento di fallback 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} ") }
}

Nota quanto segue dallo snippet:

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

Visualizzare lo stack precedente

Lo stack indietro rappresenta lo stato di navigazione dell'app. Ogni volta che lo stack indietro cambia, la UI dell'app deve riflettere il nuovo stato dello stack indietro. In Navigazione 3, un NavDisplay osserva lo stack precedente e aggiorna la relativa UI. Costruiscila con i seguenti parametri:

  • Lo stack precedente, che deve essere di tipo SnapshotStateList<T>, dove T è il tipo di chiavi dello stack precedente. È un List osservabile, quindi attiva la ricomposizione di NavDisplay quando cambia.
  • Un entryProvider per convertire le chiavi nello stack precedente in oggetti NavEntry.
  • Se vuoi, fornisci una lambda al parametro onBack. Viene chiamato quando l'utente attiva un evento Indietro.

Il seguente esempio 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 primo NavEntry dello stack precedente in un layout a un solo riquadro. La seguente registrazione mostra l'app in esecuzione:

Comportamento predefinito di `NavDisplay` con due
destinazioni.
Figura 2. Comportamento predefinito di NavDisplay con due destinazioni.

Riassumendo

Il seguente diagramma mostra il flusso di dati tra i vari oggetti in Navigazione 3:

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

  2. La modifica dello stato dello stack indietro attiva il recupero dei contenuti. NavDisplay (un composable che esegue il rendering di uno stack precedente) osserva lo stack precedente. Nella sua configurazione predefinita, mostra la voce più in alto dello stack delle attività in un layout a un solo riquadro. Quando la chiave superiore della pila posteriore cambia, NavDisplay utilizza questa chiave per richiedere i contenuti corrispondenti al fornitore della voce.

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

  4. Vengono visualizzati i contenuti. Il NavDisplay riceve il NavEntry e visualizza i contenuti.