我们在前面章回中介绍过底部导航栏的知识,如果有看官忘记的话可以点击这里查看之前的文章,本章回在此基础上添加导航功能。也就是说点击不同的底部导航标签切换到不同的页面。
回想一下,我们在使用Fragment和Activity实现底部导航时的做法:创建一个Activity并且在Activity中包含Fragment容器,通过Fragment容器来切换Fragment,进而实现底部导航功能。大家看完本章回的内容后就回来对比一下哪种方式的导航方便一些。
创建底部导航的方法和在compose中使用Navigation
库实现导航的方法类似,下面是详细的使用步骤:
介绍完创建底部导航的方法后,我们通过具体的示例代码来演示:
fun ExScaffold(
) {
//这个NavController主要用来切换底部的导航,只能在这里获取,不能在底部导航的方法中获取,不会导航栏会出现在屏幕上方
val naviController = rememberNavController()
Scaffold(
modifier = Modifier.background(color = MaterialTheme.colorScheme.primary),
topBar = { CustomCenterAppBar()},
bottomBar = { BottomNaviBarTemplate(navController = naviController)},
//控制FAB的位置,只有两种
floatingActionButtonPosition = FabPosition.End,
floatingActionButton = { CustomFAB(snackbarHostState, scope) },
) {innerPadding->
Column(modifier = Modifier
.padding(innerPadding)
.fillMaxSize()
.background(color = CusColor)
) {
Text(text = "hello")
}
//这个是自定义的页面配合自定义的底部导航栏使用:CustomBottomNavigationBar
//这个navHost容器是配合BottomNaviBarTemplate使用的,可以当作代码模板
NavHost(
navController = naviController,
startDestination = BottomNaviScreen.HomeScreen.route,
modifier = Modifier.padding(innerPadding),
) {
composable(BottomNaviScreen.PersonScreen.route) { PersonScreen(naviController)}
composable(BottomNaviScreen.HomeScreen.route) { HomeScreen(naviController) }
composable(BottomNaviScreen.SettingScreen.route) { SettingScreen(naviController) }
}
}
}
//参考官方文档编写,compose中习惯把页面叫screen,而在Flutter中习惯叫page,因此在代码中screen和page的含义相同
sealed class BottomNaviScreen(val route:String, val resourceId:Int,val icon:ImageVector) {
object PersonScreen : BottomNaviScreen("person", R.string.navi_person,Icons.Default.Person)
object HomeScreen : BottomNaviScreen("home",R.string.navi_home,Icons.Default.Home)
object SettingScreen: BottomNaviScreen("setting",R.string.navi_setting,Icons.Default.Settings)
}
//创建底部导航栏的模板代码
@Composable
fun BottomNaviBarTemplate(navController: NavController) {
val screens = listOf(
BottomNaviScreen.PersonScreen,
BottomNaviScreen.HomeScreen,
BottomNaviScreen.SettingScreen,
)
NavigationBar(
containerColor = Color.Blue,
contentColor = Color.Green, //这个颜色不起作用
) {
val navBackStackEntry by navController.currentBackStackEntryAsState()
val currentDestination = navBackStackEntry?.destination
screens.forEach { item ->
NavigationBarItem(
icon = { Icon(imageVector = item.icon, contentDescription = null)},
label = { Text(text = stringResource(id = item.resourceId))},
selected = currentDestination?.hierarchy?.any{it.route == item.route} == true,
onClick = {
navController.navigate(item.route) {
//popup to the start destination of the graph to avoid building up a large
//stack of destinations on the back stack as users select items.
popUpTo(navController.graph.startDestinationId) {
saveState = true
}
// avoid multiple copies of the same destination when reselecting the same item
launchSingleTop = true
//restore state when reselecting a previously selected item
restoreState = true
}
},
//设置bar的各种颜色
colors = NavigationBarItemDefaults.colors(
selectedIconColor = Color.Cyan,
selectedTextColor = Color.Cyan,
//这个颜色最好和NavigationBar的containerColor颜色保持一致,不然会在Icon外层显示一个背景颜色
indicatorColor = Color.Blue,
unselectedIconColor = Color.Yellow,
unselectedTextColor = Color.Yellow,
),
)
}
}
}
我们在上面的代码中添加了注释,这样方便大家理解代码,不过还有细节还需要说明:底部导航是通过Scaffold可组合函数实现的,Scaffold函数提供了槽位,我们只需要把底部导航放到槽位中就可以,同时导航容器也要放到放到Scaffold中,也就是说NavHost容器中包含所有的导航页面,需要放在Scaffold函数中,不能放在底部导航的函数中,不然导航栏会出现在屏幕上方,大家可以自己动手去试试。本示例参考了官方文档,大家可以点击这里查看官方文档中的内容。
最后,我们对本章回的内容做一个全面的总结:
看官们,与Jetpack中底部导航栏相关的内容就介绍到这里,欢迎大家在评论区交流与讨论!