Il 0% ha trovato utile questo documento (0 voti)
3 visualizzazioni32 pagine

Android LAB02 - Navigation

Il documento descrive come implementare la navigazione in un'app Compose utilizzando un grafo di navigazione, NavHost e NavController. Viene fornita una guida dettagliata per creare un'app con tre schermate, gestire le stringhe per l'internazionalizzazione e implementare rotte dinamiche. Inoltre, si accenna alla gestione delle dipendenze e all'uso di oggetti per una navigazione più sicura.

Caricato da

AlionEmini
Copyright
© All Rights Reserved
Per noi i diritti sui contenuti sono una cosa seria. Se sospetti che questo contenuto sia tuo, rivendicalo qui.
Formati disponibili
Scarica in formato PDF, TXT o leggi online su Scribd
Il 0% ha trovato utile questo documento (0 voti)
3 visualizzazioni32 pagine

Android LAB02 - Navigation

Il documento descrive come implementare la navigazione in un'app Compose utilizzando un grafo di navigazione, NavHost e NavController. Viene fornita una guida dettagliata per creare un'app con tre schermate, gestire le stringhe per l'internazionalizzazione e implementare rotte dinamiche. Inoltre, si accenna alla gestione delle dipendenze e all'uso di oggetti per una navigazione più sicura.

Caricato da

AlionEmini
Copyright
© All Rights Reserved
Per noi i diritti sui contenuti sono una cosa seria. Se sospetti che questo contenuto sia tuo, rivendicalo qui.
Formati disponibili
Scarica in formato PDF, TXT o leggi online su Scribd

Navigation

App Compose con schermate multiple

Laboratorio 2
Programmazione di Sistemi Mobile – AA 2025/2026 1
Recap: Navigazione in Compose
• Un progetto Compose che implementa le funzionalità di
navigazione è dotato di tre componenti:
– Grafo di navigazione: definisce le destinazioni raggiungibili tramite
navigazione all’interno dell’app, indicando per ciascuna il composable
che ne contiene la UI
– NavHost: è il composable utilizzato per l’implementazione del grafo
di navigazione
– NavController: è l’oggetto che gestisce la navigazione, tenendo
traccia della destinazione attuale e fornendo metodi per muoversi tra
le destinazioni definite nel grafo

Programmazione di Sistemi Mobile – AA 2025/2026 2


Esercizi
1. Navigazione in Jetpack Compose
– Con migliore gestione delle stringhe per l'internazionalizzazione
2. TravelDiary - Navigazione

Programmazione di Sistemi Mobile – AA 2025/2026 3


1. Navigazione in Jetpack Compose
• Creare un’app Compose che
permetta di navigare fra tre
schermate, come nella
figura
• Colori:
– Prima schermata:
primaryContainer
– Seconda schermata:
secondaryContainer
– Terza schermata:
tertiaryContainer

Programmazione di Sistemi Mobile – AA 2025/2026 4


1. Ingredienti
1. Composable per l'interfaccia utente
2. Installazione dipendenze
3. Definizione delle destinazioni
4. Creazione del grafo di navigazione
5. Creazione e utilizzo del NavController

Programmazione di Sistemi Mobile – AA 2025/2026 5


1.1. Composable per l'interfaccia utente
• Creare i composable per
le schermate a lato (senza
navigazione)
• Colori:
– Prima schermata:
primaryContainer
– Seconda schermata:
secondaryContainer
– Terza schermata:
tertiaryContainer

Programmazione di Sistemi Mobile – AA 2025/2026 6


Nota: navigazione type safe
• Ci sono due modi per implementare la navigazione in un'app
Jetpack Compose
• Nel primo, un po' come in un sito web, ogni schermata è
identificata da una stringa
composable("home-screen") { HomeScreen() } [Link]("home-screen")

– Benché semplice da implementare, questo metodo presenta un problema:


in fase di navigazione, non siamo in grado di stabilire se la destinazione che
forniamo esista o meno
[Link]("non-existent-screen")
Errore a runtime!

– Questo è particolarmente problematico ed error-prone in caso di rotte con


parametri, in cui è necessario creare la rotta concatenando delle stringhe:
[Link]("profile/$profileId")

Programmazione di Sistemi Mobile – AA 2025/2026 7


Nota: navigazione type safe
• Per ovviare a questo problema, dalla versione 2.8.0 della
libreria Navigation, è possibile implementare la navigazione in
un secondo modo, ossia identificando ogni schermata con un
oggetto
composable<Home> { HomeScreen() } [Link](Profile(id = profileId))

[Link](Home)
[Link](NonExistentScreen)

• Questa è l'implementazione che adotteremo per le


esercitazioni in laboratorio Errore a compile time

Programmazione di Sistemi Mobile – AA 2025/2026 8


1.2. Installazione dipendenze
• Nel file [Link] (modulo :app), aggiungere:
– Nel blocco dependencies
implementation("[Link]:navigation-compose:2.9.7") Replace with version
implementation("[Link]:ktor-serialization-kotlinx-json:2.3.8") catalog entries

– Nel blocco plugins


alias([Link])

• Nel blocco [plugins] del file [Link], aggiungere:


serialization = { id = "[Link]", [Link] = "kotlin" }

Programmazione di Sistemi Mobile – AA 2025/2026 9


1.3. Definizione delle destinazioni
• Ogni destinazione è identificata da un oggetto marcato come
@Serializable, che può essere passato al NavController
per navigare verso la schermata corrispondente
• Per un miglior livello di organizzazione e safety, è consigliabile
definire l’elenco di rotte in una sealed interface o sealed
class:
sealed interface NavigationRoute {
@Serializable data object Screen1 : NavigationRoute
@Serializable data object Screen2 : NavigationRoute
@Serializable data object Screen3 : NavigationRoute
}

Programmazione di Sistemi Mobile – AA 2025/2026 10


1.4. Creazione del grafo di navigazione
@Composable
fun NavGraph(navController: NavHostController) {
NavHost(
navController = navController,
startDestination = NavigationRoute.Screen1
) {
composable<NavigationRoute.Screen1> {
Screen1(navController)
}
composable<NavigationRoute.Screen2> {
Screen2(navController)
}
composable<NavigationRoute.Screen3> {
Screen3(navController)
}
}
}

Programmazione di Sistemi Mobile – AA 2025/2026 11


1.5. Creazione del NavController

val navController = rememberNavController()

Programmazione di Sistemi Mobile – AA 2025/2026 12


Nota: remember
• Una funzione @Composable viene rieseguita ogni volta che i suoi
parametri vengono modificati
• Per questo motivo, è preferibile non effettuare computazioni costose
all’interno dei composable
• Come già accennato in precedenza, la funzione remember permette ai
composable di computare il valore al suo interno solo durante la prima
composition, per poi salvarlo in memoria e restituirlo in tutte le
recomposition successive
val value = remember { someExpensiveFunctionReturningAValue() }

Eseguita solo una volta

Programmazione di Sistemi Mobile – AA 2025/2026 13


Nota: remember
• Il meccanismo di remember è utilizzato dalle funzioni di
moltissime librerie per Jetpack Compose
– La convenzione è di prefissare il nome di queste funzioni con la parola
remember, per indicare l’utilizzo interno di questa feature
• Un’esempio è appunto rememberNavController, che
restituisce un oggetto NavController e ne evita la ricreazione
ad ogni recomposition
val navController = rememberNavController()

Programmazione di Sistemi Mobile – AA 2025/2026 14


1.5. Creazione del NavController

MainActivity
setContent {
NavigationTheme {
val navController = rememberNavController()
NavGraph(navController)
}
}

Programmazione di Sistemi Mobile – AA 2025/2026 15


1.6. Utilizzo del navController

AppBar
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun AppBar(title: String, navController: NavHostController) {
TopAppBar(
title = { Text(title) },
navigationIcon = {
if ([Link] != null) {
IconButton(onClick = { [Link]() }) {
Icon([Link], "Go Back")
}
}
},
)
}

Programmazione di Sistemi Mobile – AA 2025/2026 16


1.5. Utilizzo del navController
Screen1
@Composable
fun Screen1(navController: NavHostController) {
Scaffold(
topBar = { AppBar("Screen1", navController) }
) { innerPadding ->
Box(
contentAlignment = [Link],
modifier = Modifier
.padding(innerPadding)
.fillMaxSize()
.background([Link])
) {
Button(
onClick = { [Link](NavigationRoute.Screen2) },
colors = [Link](
containerColor = [Link],
contentColor = [Link],
),
modifier = [Link]([Link] / 2)
) {
Text("Screen2")
}
}
}
}

Programmazione di Sistemi Mobile – AA 2025/2026 17


1.5. Utilizzo del navController
Screen1
@Composable
fun Screen1(navController: NavHostController) {
Scaffold(
topBar = { AppBar("Screen1", navController) } Naviga alla seconda
) { innerPadding ->
schermata
Box(
contentAlignment = [Link],
modifier = Modifier
.padding(innerPadding)
.fillMaxSize()
.background([Link])
) {
Button(
onClick = { [Link](NavigationRoute.Screen2) },
colors = [Link](
containerColor = [Link],
contentColor = [Link],
),
modifier = [Link]([Link] / 2)
) {
Text("Screen2")
}
}
}
}

Programmazione di Sistemi Mobile – AA 2025/2026 18


1.5. Utilizzo del navController
Screen2
@Composable
fun Screen2(navController: NavHostController) {
Scaffold(
topBar = { AppBar(stringResource([Link].screen2_name), navController) }
) { innerPadding ->
Row(
verticalAlignment = [Link],
horizontalArrangement = [Link]([Link]),
modifier = Modifier
.padding(innerPadding)
.fillMaxSize()
.background([Link])
.padding([Link])
.fillMaxWidth()
) {
val colors = [Link]([Link], [Link])
Button(
onClick = { [Link]() },
colors = colors,
modifier = [Link](1F)
) { Text(stringResource([Link].screen1_name)) }
Button(
onClick = { [Link](NavigationRoute.Screen3) },
colors = colors,
modifier = [Link](1F)
) { Text(stringResource([Link].screen3_name)) }
}
}
}

Programmazione di Sistemi Mobile – AA 2025/2026 19


1.5. Utilizzo del navController
Screen3
@Composable
fun Screen3(navController: NavHostController) {
Scaffold(
topBar = { AppBar("Screen3", navController) }
) { innerPadding ->
Box(
contentAlignment = [Link],
modifier = Modifier
.padding(innerPadding)
.fillMaxSize()
.background([Link])
) {
Button(
onClick = { [Link]() },
colors = [Link](
containerColor = [Link],
contentColor = [Link],
),
modifier = [Link]([Link] / 2)
) {
Text("Screen2")
}
}
}
}

Programmazione di Sistemi Mobile – AA 2025/2026 20


Bonus: gestione delle stringhe e internazionalizzazione

• Possiamo gestire meglio le stringhe all’interno della nostra app


• E aggiungere il supporto multilingua!

Programmazione di Sistemi Mobile – AA 2025/2026 21


Bonus: gestione delle stringhe e internazionalizzazione

1. Nel file res/values/[Link], creiamo una entry per


tutte le stringhe dell’interfaccia utente
<resources>
<string name="app_name">Navigation</string>
<string name="screen1_name">Screen1</string>
<string name="screen2_name">Screen2</string>
<string name="screen3_name">Screen3</string>
<string name="unknown_screen_name">Unknown Screen</string>
<string name="back_button_description">Go Back</string>
</resources>

Programmazione di Sistemi Mobile – AA 2025/2026 22


Bonus: gestione delle stringhe e internazionalizzazione

2. Utilizziamo i valori definiti nel file all’interno dell’app


Esempio:

Text("Screen 2") Text(stringResource([Link].screen2_name))

Programmazione di Sistemi Mobile – AA 2025/2026 23


Bonus: gestione delle stringhe e internazionalizzazione

3. Apriamo l'editor per le traduzioni, aggiungiamo la lingua


italiana e scriviamo le relative stringhe

Programmazione di Sistemi Mobile – AA 2025/2026 24


Bonus: gestione delle stringhe e internazionalizzazione

• È anche possibile creare il file manualmente

<string name="app_name">Navigation</string>
<string name="screen1_name">Schermata1</string>
<string name="screen2_name">Schermata2</string>
<string name="screen3_name">Schermata3</string>
<string name="unknown_screen_name">Schermata Sconosciuta</string>
<string name="back_button_description">Vai Indietro</string>

Programmazione di Sistemi Mobile – AA 2025/2026 25


Bonus: gestione delle stringhe e internazionalizzazione

• Cambiando la lingua del dispositivo in italiano,


cambierà anche il testo all’interno della nostra
app
– Settings → System → Languages → System
Languages → Add a Language
– Selezionare “Italiano (Italia)” e trascinarlo sopra
all’inglese

Programmazione di Sistemi Mobile – AA 2025/2026 26


2. TravelDiary - Navigazione
• Arricchire l’applicazione TravelDiary con le seguenti funzionalità:
– Navigazione tra le varie schermate
– Passaggio del travelId dalla schermata Home a TravelDetails tramite
rotta dinamica
– Bonus: condivisione del viaggio tramite Intent al click del Fab nella
schermata TravelDetails
• Potete partire dal vostro codice, oppure dalla soluzione dello
scorso laboratorio
• Alcuni indizi su come procedere nelle prossime slide
• Link alla documentazione necessaria nell’ultima slide

Programmazione di Sistemi Mobile – AA 2025/2026 27


2. TravelDiary - Navigazione

navigateUp

Intent

Programmazione di Sistemi Mobile – AA 2025/2026 28


Rotte dinamiche
• È possibile passare parametri tra due destinazioni tramite una
rotta dinamica
• Ad esempio, vogliamo passare l’ID del viaggio selezionato
quando navighiamo dalla schermata home a quella di
dettaglio:
– Definiamo una rotta TravelDetails. La rotta assume un valore
diverso in base all'ID del viaggio, pertanto non è un object, ma una
class:
@Serializable
data class TravelDetails(val travelId: String) : TravelDiaryRoute

Programmazione di Sistemi Mobile – AA 2025/2026 29


Rotte dinamiche
• Navigando verso TravelDetails("1234"), visitiamo la rotta
con travelId="1234"
• All'interno della rotta, è possibile reperire il parametro
travelId tramite la backstackEntry
composable<[Link]> { backStackEntry ->
val route = [Link]<[Link]>()
// Your screen here
}

Programmazione di Sistemi Mobile – AA 2025/2026 30


Tocca a voi!

Programmazione di Sistemi Mobile – AA 2025/2026 31


Riferimenti
• Navigation with Compose
[Link]
• Send text content via Intent
[Link]
content

Programmazione di Sistemi Mobile – AA 2025/2026 32

Potrebbero piacerti anche