Los cajones de navegación modal bloquean la interacción con el resto del contenido de una aplicación, hasta que se elige una opción o se cierra.
Se emplean principalmente en dispositivos móviles donde el espacio de la pantalla es limitado, lo más común es que se abran presionando el botón de hamburguesa de la parte superior izquierda.
Confeccionar una aplicación con tres pantalla que muestren datos generales de 3 países. Disponer un cajón de navegación que nos permita cambiar el país seleccionado.
Crear un proyecto llamado Compose17, la interfaz visual de la misma cuando el cajón de navegación esté abierto debe ser similar a:Agregamos la dependencia de Navigation Compose en el archivo Gradle:
dependencies { implementation 'androidx.core:core-ktx:1.6.0' implementation 'androidx.appcompat:appcompat:1.3.1' implementation 'com.google.android.material:material:1.4.0' implementation "androidx.compose.ui:ui:$compose_version" implementation "androidx.compose.material:material:$compose_version" implementation "androidx.compose.ui:ui-tooling-preview:$compose_version" implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.3.1' implementation 'androidx.activity:activity-compose:1.3.1' implementation("androidx.navigation:navigation-compose:2.4.0-alpha06") testImplementation 'junit:junit:4.+' androidTestImplementation 'androidx.test.ext:junit:1.1.3' androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_version" debugImplementation "androidx.compose.ui:ui-tooling:$compose_version" }
El código fuente que tenemos que implementar es:
package com.tutorialesprogramacionya.compose17 import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.compose.foundation.Image import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.* import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.verticalScroll import androidx.compose.material.* import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.* import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.painterResource import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.navigation.NavOptions import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import androidx.navigation.compose.rememberNavController import kotlinx.coroutines.launch class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { PantallaNavegacion() } } } @Composable fun PantallaNavegacion() { val navController = rememberNavController() val estadoDrawer = rememberScaffoldState() val coroutineScope = rememberCoroutineScope() Scaffold( scaffoldState = estadoDrawer, drawerContent = { Column() { Row( horizontalArrangement = Arrangement.Start, verticalAlignment = Alignment.CenterVertically, modifier = Modifier .fillMaxWidth() .padding(20.dp) .clickable { navController.navigate("pantallaargentina") coroutineScope.launch { estadoDrawer.drawerState.close() } }) { Image(imageVector = Icons.Filled.Info, contentDescription = null) Spacer(modifier = Modifier.width(15.dp)) Text(text = "Argentina",fontSize = 30.sp) } Row( horizontalArrangement = Arrangement.Start, verticalAlignment = Alignment.CenterVertically, modifier = Modifier .fillMaxWidth() .padding(20.dp) .clickable { navController.navigate("pantallabrasil") coroutineScope.launch { estadoDrawer.drawerState.close() } }) { Image(imageVector = Icons.Filled.Info, contentDescription = null) Spacer(modifier = Modifier.width(15.dp)) Text(text = "Brasil",fontSize = 30.sp) } Row( horizontalArrangement = Arrangement.Start, verticalAlignment = Alignment.CenterVertically, modifier = Modifier .fillMaxWidth() .padding(20.dp) .clickable { navController.navigate("pantallacolombia") coroutineScope.launch { estadoDrawer.drawerState.close() } }) { Image(imageVector = Icons.Filled.Info, contentDescription = null) Spacer(modifier = Modifier.width(15.dp)) Text(text = "Colombia",fontSize = 30.sp) } } }, drawerShape = RoundedCornerShape(topEnd = 23.dp, bottomEnd = 23.dp), topBar = { TopAppBar( title = { Text(text = "Países Latinoamericanos") }, navigationIcon = { IconButton(onClick = { coroutineScope.launch { estadoDrawer.drawerState.open() } }) { Icon(Icons.Filled.Menu, contentDescription = null) } } ) }, ) { NavHost(navController = navController, startDestination = "pantallaargentina") { composable("pantallaargentina") { PantallaArgentina() } composable("pantallabrasil") { PantallaBrasil() } composable("pantallacolombia") { PantallaColombia() } } } } @Composable fun PantallaArgentina() { val scroll = rememberScrollState(0) Text( text = "Argentina, oficialmente República Argentina,", modifier = Modifier.verticalScroll(scroll) ) } @Composable fun PantallaBrasil() { val scroll = rememberScrollState(0) Text( text = "Brasil, oficialmente República Federativa de Brasil", modifier = Modifier.verticalScroll(scroll) ) } @Composable fun PantallaColombia() { val scroll = rememberScrollState(0) Text( text = "Colombia, oficialmente República de Colombia", modifier = Modifier.verticalScroll(scroll) ) }
Para resolver el problema debemos definir dos variables para mantener el estado y administración de nuestro menú de cajón:
val estadoDrawer = rememberScaffoldState() val coroutineScope = rememberCoroutineScope()
Por otro lado debemos inicializar el parámetro scaffoldState con la variable de estado 'estadoDrawer', y debemos implementar la función lambda donde creamos la interfaz visual de nuestro menú de cajón y asignarla al parámetro drawerContent:
Scaffold( scaffoldState = estadoDrawer, drawerContent = { Column() { Row( horizontalArrangement = Arrangement.Start, verticalAlignment = Alignment.CenterVertically, modifier = Modifier .fillMaxWidth() .padding(20.dp) .clickable { navController.navigate("pantallaargentina") coroutineScope.launch { estadoDrawer.drawerState.close() } }) { Image(imageVector = Icons.Filled.Info, contentDescription = null) Spacer(modifier = Modifier.width(15.dp)) Text(text = "Argentina",fontSize = 30.sp) } Row( horizontalArrangement = Arrangement.Start, verticalAlignment = Alignment.CenterVertically, modifier = Modifier .fillMaxWidth() .padding(20.dp) .clickable { navController.navigate("pantallabrasil") coroutineScope.launch { estadoDrawer.drawerState.close() } }) { Image(imageVector = Icons.Filled.Info, contentDescription = null) Spacer(modifier = Modifier.width(15.dp)) Text(text = "Brasil",fontSize = 30.sp) } Row( horizontalArrangement = Arrangement.Start, verticalAlignment = Alignment.CenterVertically, modifier = Modifier .fillMaxWidth() .padding(20.dp) .clickable { navController.navigate("pantallacolombia") coroutineScope.launch { estadoDrawer.drawerState.close() } }) { Image(imageVector = Icons.Filled.Info, contentDescription = null) Spacer(modifier = Modifier.width(15.dp)) Text(text = "Colombia",fontSize = 30.sp) } } }, drawerShape = RoundedCornerShape(topEnd = 23.dp, bottomEnd = 23.dp),
La apertura del menú de cajón se dispara cuando el usuario selecciona el ícono de hamburguesa que se encuentra en la barra de la aplicación, en la parte izquierda:
topBar = { TopAppBar( title = { Text(text = "Países Latinoamericanos") }, navigationIcon = { IconButton(onClick = { coroutineScope.launch { estadoDrawer.drawerState.open() } }) { Icon(Icons.Filled.Menu, contentDescription = null) } } ) },
Este proyecto lo puede descargar en un zip desde este enlace: Compose17.zip