es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Problema de la barra de navegación inferior de Android Jetpack Compose.

A continuación se muestra una descripción general de la implementación de BottomNav. La aplicación muestra correctamente la barra de navegación inferior, pero cuando se selecciona un elemento, llama al NavHost varias veces. Veo un problema similar para las muestras de Jetpack Compose en https://github.com/android/compose-samples/tree/main/Jetsnack. ¿Hay alguna solución alternativa para evitar las múltiples llamadas a NavHost?

@Composable
fun MainScreen() {
    val navController = rememberNavController()
    Scaffold(
        bottomBar = { BottomMenu(navController = navController) }
    ) {
        BottomNavGraphBar(navController = navController)
    }
}

// manejando el evento de clic

BottomNavigationItem(

    onClick = {
        navController.navigate(screen.route) {
            popUpTo(navController.graph.findStartDestination().id)
            launchSingleTop = true
        }
    }
)


// implementación de NavHost
@Composable
fun BottomNavGraphBar(navController: NavHostController) {
    NavHost(
        navController = navController,
        startDestination = Screen.Home.route
    ) {
        composable(route = Screen.Home.route) {
            Log.d("BottomNavGraph","BottomNavGraph->HomeScreen")
            HomeScreen()
        }
        composable(route = Screen.Settings.route) {
            Log.d("BottomNavGraph","BottomNavGraph->AppSettingsScreen")
            AppSettingsScreen()
        }
        composable(route = Screen.Profile.route) {
            Log.d("BottomNavGraph","BottomNavGraph->ProfileScreen")
            ProfileScreen()
        }
    }
}

<!---LogCat--->
// Cuando se inicia la aplicación
BottomNavGraph->HomeScreen
BottomNavGraph->HomeScreen
// Se hace clic en el perfil.
BottomNavGraph->HomeScreen
BottomNavGraph->ProfileScreen
BottomNavGraph->HomeScreen
BottomNavGraph->ProfileScreen
Tags:  , , ,

Answer

  1. Avatar for davy.ai

    El problema de que NavHost se llame varias veces cuando se selecciona un elemento en BottomNav puede resolverse utilizando la función rememberSaveable para recordar la pestaña seleccionada y su estado. Esto asegura que el estado de la pestaña se mantenga y se evite llamar innecesariamente a NavHost. Además, también se puede utilizar ensureBackStackEntry para agregar la pestaña seleccionada a la pila de retroceso para poder realizar una navegación hacia arriba.

    Aquí hay un ejemplo de implementación:

    @Composable
    fun MainScreen() {
        val navController = rememberNavController()
        val bottomBarItems = listOf(BottomBarItem.Home, BottomBarItem.Settings, BottomBarItem.Profile)
        val (selectedTab, setSelectedTab) = rememberSaveable { mutableStateOf(BottomBarItem.Home) }
    
        Scaffold(
            bottomBar = {
                BottomNavigation() {
                    bottomBarItems.forEach { item ->
                        BottomNavigationItem(
                            icon = { Icon(item.icon) },
                            label = { Text(item.title) },
                            selected = selectedTab == item,
                            onClick = {
                                setSelectedTab(item)
                                navController.navigate(item.route) {
                                    // Agregar a la pila de retroceso para admitir la navegación hacia arriba
                                    ensureBackStackEntry(item.route)
                                }
                            }
                        )
                    }
                }
            }
        ) {
            // Seleccionar manualmente la pestaña cuando se abre la pantalla
            when (selectedTab) {
                BottomBarItem.Home -> HomeScreen()
                BottomBarItem.Settings -> AppSettingsScreen()
                BottomBarItem.Profile -> ProfileScreen()
            }
        }
    }
    
    // Rutas de navegación
    sealed class BottomBarItem(val icon: ImageVector, val title: String, val route: String) {
        object Home : BottomBarItem(Icons.Filled.Home, "Inicio", "inicio")
        object Settings : BottomBarItem(Icons.Filled.Settings, "Configuración", "configuracion")
        object Profile : BottomBarItem(Icons.Filled.Person, "Perfil", "perfil")
    }
    
    // Función de utilidad para garantizar la pila de retroceso
    fun NavController.ensureBackStackEntry(route: String) {
        val currentBackStackEntry = currentBackStackEntry?.destination
        if (currentBackStackEntry?.route != route) {
            val navOptions = NavOptions.Builder()
                .setLaunchSingleTop(true)
                .setPopUpTo(route, false)
                .build()
            navigate(route, navOptions)
        }
    }
    

    Con esta implementación, la pestaña seleccionada se recuerda y no se llama innecesariamente a NavHost varias veces. Además, la función ensureBackStackEntry garantiza que la pestaña seleccionada se agregue a la pila de retroceso y admita la navegación hacia arriba.

Comments are closed.