Bottom Navigation Bar - Material3

Very simple example of a Jetpack Compose Kotlin app using a Material3 bottom navigation bar.
 avatar
unknown
kotlin
a year ago
4.7 kB
9
Indexable
// MainActivity.kt
MyAppNameComposeTheme {
    val navController = rememberNavController()

    Scaffold(
        bottomBar = {
            BottomNavigationBar(
                items = listOf(
                    BottomNavigationItem(
                        name = "Item One",
                        route = MyAppScreen.Home.route,
                        selectedIcon = Icons.Filled.Home,
                        unselectedIcon = Icons.Outlined.Home
                    ),
                    BottomNavigationItem(
                        name = "Item Two",
                        route = MyAppScreen.Blah.route,
                        selectedIcon = Icons.Filled.Note,
                        unselectedIcon = Icons.Outlined.Note
                    ),
                    BottomNavigationItem(
                        name = "Item Three",
                        route = MyAppScreen.Lolwut.route,
                        selectedIcon = Icons.Filled.Settings,
                        unselectedIcon = Icons.Outlined.Settings
                    )
                ),
                onItemClick = {
                    navController.navigate(route = it.route)
                })
        }
    ) { padding ->
        MyAppNavigation(navController = navController, padding)
    }
}

// MyAppScreen.kt
sealed class MyAppScreen(val route: String, val name: String) {
    object Home: MyAppScreen(route = "homie", name = "Home")
    object Blah: MyAppScreen(route = "blah", name = "Blah blah blah")
    object Lolwut: MyAppScreen(route = "lol_wut", name = "lol wut")
}

// MyAppNavigation.kt
@Composable
fun MyAppNavigation(
    navController: NavHostController = rememberNavController(),
    parentPadding: PaddingValues = PaddingValues()
) {
    NavHost(
        navController = navController,
        startDestination = MyAppScreen.Home.route
    ) {
        composable(MyAppScreen.Home.route) {
            HomeScreen(
                navController = navController,
                vm = hiltViewModel<HomeViewModel>()
            )
        }

        composable(
            route = ShotTrackerScreen.Blah.route + "?myThingId={thingId}",
            arguments = listOf(
                navArgument(name = "thingId") {
                    type = NavType.IntType
                    defaultValue = -1
                }
            )
        ) {
            BlahScreen(
                navController = navController,
                modifier = Modifier
                    .background(
                        Brush.verticalGradient(
                            listOf(
                                MaterialTheme.colors.surface,
                                MaterialTheme.colors.primaryVariant
                            )
                        )
                    ),
                viewModel = hiltViewModel<BlahViewModel>()
            )
        }

        // and so on, your screen composables go here for each of your app's main screens/pages 
        // that you can nav to from the menu/nav system (in this case, bottom nav bar)
    }
}

// BottomNavigationBar.kt
@Composable
fun BottomNavigationBar(
    items: List<BottomNavigationItem>,
    modifier: Modifier = Modifier,
    backgroundColor: Color = MaterialTheme.colors.surface,
    elevation: Dp = 5.dp,
    onItemClick: (BottomNavigationItem) -> Unit
) {
    var selectedItemIndex by rememberSaveable {
        mutableStateOf(0)
    }

    NavigationBar(
        modifier = modifier,
        containerColor = backgroundColor,
        tonalElevation = elevation
    ) {
        items.forEachIndexed { index, navItem ->
            val isItemSelected = selectedItemIndex == index
            val currentItemIcon = if (isItemSelected) navItem.selectedIcon else navItem.unselectedIcon

            NavigationBarItem(
                selected = isItemSelected,
                onClick = {
                    selectedItemIndex = index

                    onItemClick(navItem)
                },
                icon = {
                    Column(
                        horizontalAlignment = Alignment.CenterHorizontally
                    ) {
                        Icon(
                            imageVector = currentItemIcon,
                            contentDescription = navItem.name
                        )

                        Text(
                            text = navItem.name,
                            textAlign = TextAlign.Center,
                            fontSize = 10.sp
                        )
                    }
                }
            )
        }
    }
}


data class BottomNavigationItem(
    val name: String,
    val route: String,
    val selectedIcon: ImageVector,
    val unselectedIcon: ImageVector
)