13 - Componente BottomNavigation (funciones BottomNavigation, BottomNavigationItem y Scaffold)

La barra de navegación inferior (BottomNavigation) permite el movimiento entre distintos principales de una aplicación.

Esta componente pertenece a Material Design y como tal para una correcta integración deberemos utilizar la componente Scaffold.

Scaffold implementa la estructura de disposición visual básica del diseño de Material Design. Este componente proporciona un API para unir varios componentes de material para construir su pantalla, asegurando una estrategia de diseño adecuada para ellos y recopilando los datos necesarios para que estos componentes funcionen juntos correctamente.

Problema

Confeccionar una aplicación con tres pantalla que muestren datos generales de 3 paises. Disponer una barra de navegación inferior para poder seleccionar un país específico.

Crear un proyecto llamado Compose15, la interfaz visual de la misma debe ser similar a:

BottomNavigation Jetpack Compose

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 debemos implementar es:

package com.tutorialesprogramacionya.compose15


import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.rememberScrollState
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.Modifier
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            PantallaNavegacion()
        }
    }
}

@Composable
fun PantallaNavegacion() {
    val navController = rememberNavController()
    Scaffold(
        bottomBar = {
            BottomNavigation() {
                var argentina by remember { mutableStateOf(true) }
                var colombia by remember { mutableStateOf(false) }
                var brasil by remember { mutableStateOf(false) }
                BottomNavigationItem(selected = argentina,
                    onClick = {
                        argentina = true;colombia = false;brasil = false;
                        navController.navigate("pantallaargentina")
                    },
                    icon = { Icon(Icons.Default.Info, contentDescription = null) },
                    label = {
                        Text(text = "Argentina")
                    }
                )
                BottomNavigationItem(selected = brasil,
                    onClick = {
                        brasil = true;argentina = false;colombia = false;
                        navController.navigate("pantallabrasil")
                    },
                    icon = { Icon(Icons.Default.Info, contentDescription = null) },
                    label = {
                        Text(text = "Brasil")
                    }
                )
                BottomNavigationItem(selected = colombia,
                    onClick = {
                        colombia = true;argentina = false;brasil = false;
                        navController.navigate("pantallacolombia")
                    },
                    icon = { Icon(Icons.Default.Info, contentDescription = null) },
                    label = {
                        Text(text = "Colombia")
                    }
                )
            }
        }
    ) {
        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)
    )
}

En la función 'PantallaNavegacion' creamos un controlador de navegación, en forma idéntica al concepto anterior:

    val navController = rememberNavController()

Llamamos a la función Scaffold y le pasamos un único parámetro llamado 'bottomBar' con una función lambda donde procedemos a llamar en su interior a la función BottomNavigation y en su interior llamamos tres veces a la función 'BottomNavigationItem', una por cada país. Para mostrar activo el último BottomNavigationItem presionado definimos las variables de estado argentina, colombia y brasil

    Scaffold(
        bottomBar = {
            BottomNavigation() {
                var argentina by remember { mutableStateOf(true) }
                var colombia by remember { mutableStateOf(false) }
                var brasil by remember { mutableStateOf(false) }
                BottomNavigationItem(selected = argentina,
                    onClick = {
                        argentina = true;colombia = false;brasil = false;
                        navController.navigate("pantallaargentina")
                    },
                    icon = { Icon(Icons.Default.Info, contentDescription = null) },
                    label = {
                        Text(text = "Argentina")
                    }
                )
                BottomNavigationItem(selected = brasil,
                    onClick = {
                        brasil = true;argentina = false;colombia = false;
                        navController.navigate("pantallabrasil")
                    },
                    icon = { Icon(Icons.Default.Info, contentDescription = null) },
                    label = {
                        Text(text = "Brasil")
                    }
                )
                BottomNavigationItem(selected = colombia,
                    onClick = {
                        colombia = true;argentina = false;brasil = false;
                        navController.navigate("pantallacolombia")
                    },
                    icon = { Icon(Icons.Default.Info, contentDescription = null) },
                    label = {
                        Text(text = "Colombia")
                    }
                )
            }
        }
    ) {
        NavHost(navController = navController, startDestination = "pantallaargentina") {
            composable("pantallaargentina") {
                PantallaArgentina()
            }
            composable("pantallabrasil") {
                PantallaBrasil()
            }
            composable("pantallacolombia") {
                PantallaColombia()
            }
        }
    }

A la función Scaffold le pasamos la función lamda con la llamada a la función NavHost.

Las funciones composables que muestran información de cada país no tienen nada de especial:

@Composable
fun PantallaArgentina() {
    val scroll = rememberScrollState(0)
    Text(
        text = "Argentina, oficialmente República Argentina",
        modifier = Modifier.verticalScroll(scroll)
    )
}

Este proyecto lo puede descargar en un zip desde este enlace: Compose15.zip