Material3 ‐ Bottom Navigation Bar - devrath/Material-3-Design-Kit GitHub Wiki

Contents
Observation
Demo representation
Code

Observation

  • We use the bottom navigation bar when there is a minimum of 3 tabs and a maximum of 5

Untitled Diagram drawio

Demo representation

Light Theme Dark Theme

Code

BottomNavigationItem.kt Contains the data for the Navigation Tab to hold the states

sealed class BottomNavigationItem(
    val route:String,
    val iconSelected: ImageVector,
    val iconUnSelected: ImageVector,
    val title: String = ""
){
    // <--------- Home Screen --------->
    object Home : BottomNavigationItem(
        route = "home",
        title = "Home",
        iconSelected = Icons.Filled.Home,
        iconUnSelected = Icons.Outlined.Home,
    )
    // <--------- Chat Screen --------->
    object Chat : BottomNavigationItem(
        route = "chat",
        title = "Settings",
        iconSelected = Icons.Filled.ChatBubble,
        iconUnSelected = Icons.Outlined.ChatBubble,
    )
    // <--------- Settings Screen --------->
    object Settings : BottomNavigationItem(
        route = "settings",
        title = "Settings",
        iconSelected = Icons.Filled.Settings,
        iconUnSelected = Icons.Outlined.Settings,
    )
}

NavScreens.kt Contains all the screens

@Composable
fun ScreenHome() {
    CommonScreen(screenName = "Home", backgroundColor = Color.DarkGray)
}

@Composable
fun ScreenChat() {
    CommonScreen(screenName = "Chat", backgroundColor = Color.Magenta)
}

@Composable
fun ScreenSettings() {
    CommonScreen(screenName = "Settings", backgroundColor = Color.Cyan)
}


@Composable
private fun CommonScreen(screenName: String, backgroundColor: Color) {
    Column(
        modifier = Modifier
            .fillMaxSize()
            .background(color = backgroundColor),
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        Text(
            modifier = Modifier.fillMaxWidth(),
            fontSize = 30.sp,
            textAlign = TextAlign.Center,
            fontFamily = FontFamily.Monospace,
            style = TextStyle(
                color = Color.White
            ),
            text = screenName
        )
    }
}

@Preview
@Composable
private fun CurrentScreen() {
    ScreenHome()
}

NavigationGraph.kt It contains all a navigation host that holds all the screen composables

// Navigation graph: Contains all the screens as composable in a NavHost
@Composable
fun NavigationGraph(navController: NavHostController) {
    NavHost(
        navController = navController,
        startDestination = BottomNavigationItem.Home.route
    ) {
        composable(route = BottomNavigationItem.Home.route) {
            ScreenHome()
        }
        composable(route = BottomNavigationItem.Chat.route) {
            ScreenChat()
        }
        composable(route = BottomNavigationItem.Settings.route) {
            ScreenSettings()
        }
    }
}

BottomNavContent.kt Content composable that holds scaffold that in turn holds bottom bar and navigation host

@Composable
fun BottomNavContent(modifier: Modifier = Modifier) {

    // Data items to have the Bottom tabs
    val navItems = remember {
        mutableStateListOf(
            BottomNavigationItem.Home,
            BottomNavigationItem.Chat,
            BottomNavigationItem.Settings
        )
    }

    // The state "rememberSavable" helps to save the state in configuration changes, We can save in viewmodel also
    var selectedItemIndex by rememberSaveable { mutableIntStateOf(0) }
    // Keeping track of navigation
    val navController = rememberNavController();
    // Scaffold: it contains bottom navigation bar and a NavHost(Contains all screens) for each screen
    Scaffold(
        bottomBar = {
            NavigationBar {
                navItems.forEachIndexed { index, item ->
                    NavigationBarItem(
                        // If both the index are same, return true indicating it is selected
                        selected = (selectedItemIndex == index),
                        onClick = {
                            selectedItemIndex = index
                            navController.navigate(item.route)
                        },
                        label = {
                            Text(text = item.title)
                        },
                        icon = {
                            Icon(
                                imageVector = if (selectedItemIndex == index) {
                                    item.iconSelected
                                } else {
                                    item.iconUnSelected
                                },
                                contentDescription = item.title
                            )
                        },
                    )
                }
            }
        }
    ) {
        Column(
            modifier = Modifier
                .fillMaxSize()
                .padding(it)
        ) {
            NavigationGraph(navController)
        }
    }
}

BottomNavigationBarActivity.kt Activity that contains a single composable holding the content of the screen

class BottomNavigationBarActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            MaterialAppTheme {
                // A surface container using the 'background' color from the theme
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colorScheme.background
                ) {
                    ScreenContent()
                }
            }
        }
    }
}

@Composable
fun ScreenContent(modifier: Modifier = Modifier) {
    BottomNavContent()
}

@Preview(showBackground = true)
@Composable
fun CurrentScreenPreview() {
    MaterialAppTheme {
        ScreenContent()
    }
}
⚠️ **GitHub.com Fallback** ⚠️