El component de navegació fa servir un graf de navegació per gestionar la navegació de la teva aplicació.
Introducció
El Navigation component utilitza un graf de navegació per gestionar la navegació de la teva aplicació.
El graf de navegació és l’estructura de dades que conté cada destinació dins la teva aplicació i la connexió entre elles.
El graf de navegació és diferent de la back stack, que és una pila dins del NavController que conté les destinacions que l’usuari ha visitat recentment.
Hi ha tres tipus de destinacions: hosted, dialog, i activity.
Les destinacions “hosted” són les que s’utilitzen amb més freqüència, i ocupen tota la pantalla del’amfitrió.
Entorn de treball
Crea un nou projecte compose-navigation amb Amper
Habilita la serialització i afegeix una dependència amb la biblioteca navigation-compose: module.yaml
Navegació
A continuació tens una aplicació d’exemple amb dues pantalles (“screens”).
Modifica el fitxer src/main.kt:
import androidx.compose.foundation.layout.Columnimport androidx.compose.material.Buttonimport androidx.compose.material.MaterialThemeimport androidx.compose.material.Textimport androidx.compose.runtime.*
import androidx.navigation.NavControllerimport androidx.navigation.compose.NavHostimport androidx.navigation.compose.composableimport androidx.navigation.compose.rememberNavControllerimport kotlinx.serialization.Serializable
@Composablefun App() { MaterialTheme { val controller = rememberNavController() NavHost(controller, startDestination = HomeRoute) { composable<HomeRoute> { HomeScreen(controller) } composable<CityRoute> { CityScreen() } } }}
@Serializableobject HomeRoute
@Composablefun HomeScreen(controller: NavController) {
Column { Text("Home") Button(onClick = { controller.navigate(CityRoute) }) { Text("City") } }}
@Serializableobject CityRoute
@Composablefun CityScreen() { Text("Barcelona")}Amb la funció “composable” NavHost crees un graf de navegació.
En cridar la funció “composable” NavHost passem com a paràmetres un NavController i una ruta pel destí inicial (la ruta Home).
Amb la funció composable() defineixes quin “composable” es el destí d’una “ruta”.
Quan defineixes una ruta mai has de dir de quin “screen” ha de venir, sinó quin “screen” ha de gestionar la “ruta”.
Amb la tecla Esc pots navegar cap enrere.
Activitat
Afegeix un nova pàgina CountryScreen.
@Composablefun App() { val controller = rememberNavController() NavHost(controller, startDestination = HomeRoute) { composable<HomeRoute> { HomeScreen(controller) } composable<CityRoute> { CityScreen() } composable<CountryRoute> { CountryScreen() } }}
@Serializableobject CountryRoute
@Composablefun CountryScreen() { Text("Country")}Afegeix un botó aHomeScreen que et porti aCountryScreen.
@Composablefun HomeScreen(controller: NavController) {
Column { Text("Home") Button(onClick = {controller.navigate(CityRoute)}) { Text("City") } Button(onClick = {controller.navigate(CountryRoute)}) { Text("Country") } }}Afegeix un botó aCountryScreen que et porti aCiytScreen.
@Composablefun HomeScreen(controller: NavController) {
Column { Text("Home") Button(onClick = {controller.navigate(CityRoute)}) { Text("City") } Button(onClick = {controller.navigate(CountryRoute)}) { Text("Country") } }}Afegeix una barra de navegació(TopAppBar):
@Composablefun Nav(controller: NavController) { TopAppBar( title = {Text("Geography")}, actions = { IconButton(onClick = {controller.navigate(HomeRoute)}) { Icon(imageVector = Icons.Filled.Home, contentDescription = "Home") } })}
@Composablefun HomeScreen(controller: NavController) {
Column { Nav(controller) Button(onClick = {controller.navigate(CityRoute)}) { Text("City") } Button(onClick = {controller.navigate(CountryRoute)}) { Text("Country") } }}
// ...Paràmetres
Si vols passar paràmetres a un “screen” has d’utlitzar un data class enlloc d’un object.
@Serializabledata class CityRoute(val name: String)Ara el componentHomeScreen ja pot utilitzar la nova ruta:
@Composablefun HomeScreen(controller: NavController) {
// ... Button(onClick = { controller.navigate(CityRoute("Girona")) }) { Text("City") } // ... }}ElNavHost ha de configurar la ruta passantCityRoute a CityScreen:
@Composablefun App() { MaterialTheme { val controller = rememberNavController() NavHost(controller, startDestination = HomeRoute) { composable<HomeRoute> { HomeScreen(controller) } composable<CityRoute> { entry -> CityScreen(controller, entry.toRoute()) } composable<CountryRoute> { CountryScreen(controller) } } }}El componentCityScreen ha d’acceptar com a paràmetre CityRoute:
@Composablefun CityScreen(controller: NavController, route: CityRoute) { Column { Nav(controller) Text(route.name) }}Ara CityScreen mostra la ciutat que li passen com a paràmetre.
Afegeix unTextField aHomeScreen on l’usuari pugui posar la ciutat que vulgui i al apretar el botó passi el contingut com a paràmetre:
@Composablefun HomeScreen(controller: NavController) {
// ... Row( modifier = Modifier.padding(8.dp) ) { TextField( value = city.value, placeholder = {Text("City Name")}, onValueChange = {city.value = it}) Button( onClick = {controller.navigate(CityRoute(city.value))} ) { Text("City View") } } // ...
}Crea un “screen”Countries que mostri una llista de paisos:
val countries = listOf("Spain", "France", "Italy", "Portugal", "Germany")
@Serializableobject CountryListRoute
@Composablefun CountryListScreen(controller: NavController) { Column { Nav(controller) LazyColumn() {items(countries) {country -> Text(text = country)}} }}Afegeix un enllaç del “screen” a la barra de navegació
@Composablefun Nav(controller: NavController) { TopAppBar( title = {Text("Geography")}, actions = { IconButton(onClick = {controller.navigate(HomeRoute)}) { Icon(imageVector = Icons.Filled.Home, contentDescription = "Home") } IconButton(onClick = {controller.navigate(CountryListRoute)}) { Text("Countries") } } )}Fes que la llista de països sigui clicable i navegui al “screen” Country:
@Composablefun CountryListScreen(controller: NavController) { Column { Nav(controller) LazyColumn() { items(countries) {country -> Row( modifier = Modifier.clickable {controller.navigate(CountryRoute(country))} .padding(4.dp) .border(1.dp, color = MaterialTheme.colors.primary, CircleShape) .padding(4.dp).fillMaxWidth() ) { Text(text = country) }}}}}Fes el mateix amb un “screen” Cities.