Jetpack Compose Bottom Navigation With Scaffold (Material3)

What is a Scaffold?

In Material Design, a scaffold is a fundamental structure that provides a standardized platform for complex user interfaces. It holds together different parts of the UI, such as app bars and floating action buttons, and the bottom bar gives apps a coherent look and feel.

Scaffold accepts several composables as parameters. Among these are the following:

  • topBar: The app bar is across the top of the screen.
  • bottomBar: The app bar is across the bottom of the screen.
  • floatingActionButton: A button that hovers over the bottom-right corner of the screen that you can use to expose key actions.

In this example, we will include topBar and bottomBar with the complete example.

Let’s start it

I hope you have set up the latest libs and material3 with the latest Android studio version. We also include one case where you want to hide the bottom bar.

Define Main Screen NavHost which will be responsible for showing Main Screens Home And Settings.

@Composable
fun BottomNavWithScaffold(
) {
    val navController = rememberNavController()
    NavHost(
        navController = navController,
        startDestination = NavRoute.Home.route,
        modifier = Modifier.fillMaxSize()
    ) {
        composable(route = NavRoute.Home.route) {
            HomeScreen() {
                navController.navigate(it)
            }
        }
        composable(route = NavRoute.Settings.route) {
            SettingsScreen()
        }
    }
}

Now, we will make another NavHost which contains the BottomBar and three screen with Scaffold .

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun HomeScreen(
    navigateTo: (route: String) -> Unit
) {

    val topLevelDestinations = listOf(
        TopLevelDestination(
            route = NavRoute.Screen1.route,
            selectedIcon = R.drawable.home,
            unselectedIcon = R.drawable.home_outline,
            iconText = "Home"
        ), TopLevelDestination(
            route = NavRoute.Screen2.route,
            selectedIcon = R.drawable.bulb,
            unselectedIcon = R.drawable.bulb_outline,
            iconText = "Generate"
        ), TopLevelDestination(
            route = NavRoute.Screen3.route,
            selectedIcon = R.drawable.my_files,
            unselectedIcon = R.drawable.my_files_outline,
            iconText = "My Files"
        )
    )

    val showBottomBar = remember { mutableStateOf(true) }
    val title = remember {
        mutableStateOf("Home")
    }
    val navController = rememberNavController()

    Scaffold(
        topBar = {
            CenterAlignedTopAppBar(title = {
                Text(
                    text = title.value,
                    color = Color.White,
                    fontWeight = FontWeight.Bold,
                    fontSize = 20.sp,
                )
            }, colors = TopAppBarDefaults.centerAlignedTopAppBarColors(
                containerColor = MaterialTheme.colorScheme.primary
            ), actions = {
                Icon(
                    imageVector = Icons.Filled.Settings,
                    tint = MaterialTheme.colorScheme.onPrimary,
                    contentDescription = "Settings",
                    modifier = Modifier
                        .clickable {
                            navigateTo(NavRoute.Settings.route)
                        }
                        .padding(8.dp)
                )
            })
        },
        bottomBar = {
            if (showBottomBar.value) {
                HomeBottomBar(destinations = topLevelDestinations,
                    currentDestination = navController.currentBackStackEntryAsState().value?.destination,
                    onNavigateToDestination = {
                        title.value = when (it) {
                            "sc1" -> "Screen 1"
                            "sc2" -> "Screen 2"
                            else -> {
                                "Screen 3"
                            }
                        }
                        navController.navigate(it) {
                            popUpTo(navController.graph.findStartDestination().id) {
                                saveState = true
                            }
                            restoreState = true
                            launchSingleTop = true
                        }
                    })
            }
        }
    ) {
        Column(
            modifier = Modifier
                .padding(it)
                .fillMaxSize()
        ) {
            HomeNavHost(
                modifier = Modifier
                    .fillMaxSize()
                    .weight(1f),
                navController = navController,
                startDestination = NavRoute.Screen1.route,
                navigateTo = navigateTo
            )

        }
    }
}
  • topLevelDestinations: We have made one data class that will hold the icons, text and route for BottomNav.
  • Scaffold: It is responsible for holding all the UI of the screen together.
  • CenterAlignedTopAppBar : This is responsible for showing the Title, Navigation Icon, Menu, etc.
  • HomeNavHost : This will hold all three screens and also change the TopAppBar title when we switch the screen using a bottom bar.
@Composable
fun HomeNavHost(
    modifier: Modifier,
    navController: NavHostController,
    startDestination: String,
    navigateTo: (route: String) -> Unit
) {

    NavHost(
        navController = navController, startDestination = startDestination, modifier = modifier
    ) {

        composable(route = NavRoute.Screen1.route) {
            Screen1()
        }
        composable(route = NavRoute.Screen2.route) {
            Screen2()
        }
        composable(route = NavRoute.Screen3.route) {
            Screen3()
        }


    }
}
@Composable
fun Screen1() {
    Column(modifier = Modifier.fillMaxSize()) {
        Text(text = "One Screen", fontSize = 20.sp)
    }
}

@Composable
fun Screen2() {
    Column(modifier = Modifier.fillMaxSize()) {
        Text(text = "Two Screen", fontSize = 20.sp)
    }
}

@Composable
fun Screen3() {
    Column(modifier = Modifier.fillMaxSize()) {
        Text(text = "Three Screen", fontSize = 20.sp)
    }
}

Sample Screen PlaceHolders

Bottombar Item Design

@Composable
private fun HomeBottomBar(
    destinations: List<TopLevelDestination>,
    currentDestination: NavDestination?,
    onNavigateToDestination: (route: String) -> Unit
) {

        NavigationBar(
            modifier = Modifier
                .windowInsetsPadding(
                    WindowInsets.safeDrawing.only(WindowInsetsSides.Horizontal + WindowInsetsSides.Bottom)
                )
                .height(70.dp),
        ) {
            destinations.forEach { destination ->
                val selected =
                    currentDestination?.hierarchy?.any { it.route == destination.route } == true
                NavigationBarItem(
                    selected = selected,
                    onClick = { onNavigateToDestination(destination.route) },
                    icon = {
                        val icon = if (selected) {
                            destination.selectedIcon
                        } else {
                            destination.unselectedIcon
                        }
                        Icon(
                            imageVector = ImageVector.vectorResource(icon),
                            modifier = Modifier.size(16.dp),
                            contentDescription = null
                        )
                    },
                    label = {
                        Text(
                            text = destination.iconText
                        )
                    })
            }
        }
}

That’s it. We have made an app that contains the BottomNavigation with Different Screens And Navigation Best Practices.

🍴Check out the complete code on my GitHub Repository. ✍️ Hope this project really helps you.

Hope you enjoy coding Jetpack Compose 😁. Don’t forget to share 📨 and clap 👏.

Any Suggestions are welcome. If you need any help or have questions for Code Contact Me. You can follow me on LinkedInStackOverflow and Twitter For More Updates 🔔

Happy Compose !! 🚀

Preview

Leave a Reply

Your email address will not be published. Required fields are marked *