Search code examples
androidkotlinandroid-jetpack-composebottomnavigationviewandroid-navigation-bar

The screens of BottomNavigationBar is not showing


I have a bottomNavigtionBar with jetpack compose but the screens are not showing when I navigate between it, it's showing the bottom bar with a blank white page

enter image description here

I have three screens Home, Profile and Settings

@Composable
fun HomeThirdScreen() {
    Box(
        modifier = Modifier
            .fillMaxSize()
            .background(Color.Blue),
        contentAlignment = Alignment.Center
    ) {
        Text(
            text = "Home",
            fontSize = MaterialTheme.typography.headlineLarge.fontSize,
            fontWeight = FontWeight.Bold,
            color = Color.White
        )

    }
}


@Preview
@Composable
fun PreviewHomeThirdScreen() {
    HomeThirdScreen()
}

Profile Screen

@Composable
fun ProfileScreen() {
    Box(
        modifier = Modifier
            .fillMaxSize()
            .background(Color.Magenta),
        contentAlignment = Alignment.Center
    ) {
        Text(
            text = "Profile",
            fontSize = MaterialTheme.typography.headlineLarge.fontSize,
            fontWeight = FontWeight.Bold,
            color = Color.White
        )

    }
}


@Preview
@Composable
fun PreviewProfileScreen() {
    ProfileScreen()
}

Settings screen

@Composable
fun SettingsScreen() {
    Box(
        modifier = Modifier
            .fillMaxSize()
            .background(Color.Gray),
        contentAlignment = Alignment.Center
    ) {
        Text(
            text = "Settings",
            fontSize = MaterialTheme.typography.headlineLarge.fontSize,
            fontWeight = FontWeight.Bold,
            color = Color.White
        )

    }
}


@Preview
@Composable
fun PreviewSettingsScreen() {
    SettingsScreen()
}

and this BottomBarScreen class

sealed class BottomBarScreen(
    val route:String,
    val title:String,
    val icon:ImageVector
){
    object Home:BottomBarScreen(
        route = "home",
        title = "Home",
        icon = Icons.Default.Home
    )

    object Profile:BottomBarScreen(
        route = "profile",
        title = "Profile",
        icon = Icons.Default.AccountCircle
    )

    object Settings:BottomBarScreen(
        route = "settings",
        title = "Settings",
        icon = Icons.Default.Settings
    )
}

and this BottomNavGraph

@Composable
fun BottomNavGraph(navHostController: NavHostController) {

    NavHost(navController = navHostController, startDestination = BottomBarScreen.Home.route){

        composable(route = BottomBarScreen.Home.route){
            HomeThirdScreen()
        }
        composable(route = BottomBarScreen.Profile.route){
            ProfileScreen()
        }

        composable(route = BottomBarScreen.Settings.route){
            SettingsScreen()
        }
    }

}

and this main screen code

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun MainScreen() {

    val navHostController = rememberNavController()

    BottomNavGraph(navHostController = navHostController)

    val screens = listOf(
        BottomBarScreen.Home,
        BottomBarScreen.Profile,
        BottomBarScreen.Settings
    )

    val navBackStackEntry by navHostController.currentBackStackEntryAsState()
    val currentDestination = navBackStackEntry?.destination

    var selectedItemIndex by rememberSaveable {
        mutableIntStateOf(0)
    }


        Scaffold(
            bottomBar = {
            NavigationBar {
                screens.forEachIndexed { index, bottomBarScreen ->

                    NavigationBarItem(selected = currentDestination?.hierarchy?.any {
                        it.route == bottomBarScreen.route } == true,
                        label = { Text(text = bottomBarScreen.title) },
                        onClick = {
                            selectedItemIndex = index
                            navHostController.navigate(bottomBarScreen.route)
                        },
                        icon = {
                            Icon(
                                imageVector = bottomBarScreen.icon,
                                contentDescription = bottomBarScreen.title
                            )
                        })
                }
            }
        }) {
            it.calculateTopPadding()
            it.calculateBottomPadding()
           it.calculateEndPadding(LayoutDirection.Ltr)
           it.calculateStartPadding(LayoutDirection.Ltr)


        }
}

and finally, I called the MainScreen Composable here

override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            Surface(modifier = Modifier.fillMaxSize(),
                color = MaterialTheme.colorScheme.surface
                ) {
                MainScreen()
            }


        }
    }

Solution

  • I don't think you understand the concept of a NavHost it's not just a function that controls navigation its also a composable that acts like a container o for it's destinations. The problem in your code is that you are calling BottomNavGraph outside your main composable container in your case Scaffold so even though you are navigating to the screen it will not show because of the Scaffold shadowing it. You should do it like this:

    @OptIn(ExperimentalMaterial3Api::class)
    @Composable
    
    fun MainScreen() {
    
    val navHostController = rememberNavController()
    
    val screens = listOf(
        BottomBarScreen.Home,
        BottomBarScreen.Profile,
        BottomBarScreen.Settings
    )
    
    val navBackStackEntry by navHostController.currentBackStackEntryAsState()
    val currentDestination = navBackStackEntry?.destination
    
    var selectedItemIndex by rememberSaveable {
        mutableIntStateOf(0)
    }
    
    
        Scaffold(
            bottomBar = {
            NavigationBar {
                screens.forEachIndexed { index, bottomBarScreen ->
    
                    NavigationBarItem(selected = currentDestination?.hierarchy?.any {
                        it.route == bottomBarScreen.route } == true,
                        label = { Text(text = bottomBarScreen.title) },
                        onClick = {
                            selectedItemIndex = index
                            navHostController.navigate(bottomBarScreen.route)
                        },
                        icon = {
                            Icon(
                                imageVector = bottomBarScreen.icon,
                                contentDescription = bottomBarScreen.title
                            )
                        })
                }
            }
        }) {
            it.calculateTopPadding()
            it.calculateBottomPadding()
           it.calculateEndPadding(LayoutDirection.Ltr)
           it.calculateStartPadding(LayoutDirection.Ltr)
    BottomNavGraph(navHostController = navHostController)
    
        }
    }