做主页导航时会用到底部导航栏,Jetpack Compose提供了基础槽位的布局Scaffold,使用Scaffold可以构建底部导航栏,例如:

@Composable
fun Greeting(vm: VM) {
val list = listOf("One", "Two", "Three")
var selectedItem = remember {
mutableStateOf(0)
}
val navController = rememberNavController() Scaffold(bottomBar = {
state.takeIf { it.value }?.let {
BottomNavigation {
list.forEachIndexed { index, label ->
BottomNavigationItem(
label = { Text(text = label) },
selected = index == selectedItem.value,
onClick = { selectedItem.value = index },
icon = {
Icon(
painter = painterResource(id = R.drawable.ic_launcher_foreground),
contentDescription = null
)
})
}
}
}
}) {
NavHost(navController = navController, startDestination = "one") {
composable(route = "one") { PageList(navController, vm) }
composable(route = "detail") { PageDetail(vm) }
}
}
}

这是一个最简单的Scaffold,其主页时PageList,显示一列数字,点击数字后会跳转到PageDetail页面。

但是有个很大的问题,就是在跳转到PageDetail页面之后,BottomNavigation并没有随之消失,于是乎出现了这样一个奇怪的现象:

为了解决这个问题,可以采用State去控制BottomNavigation的可见性,并将其保存在ViewModel中。

具体做法是:

1.在ViewModel中创建一个包含Boolean值的LiveData变量state。当state为true时绘制BottomNavigation,为false时不绘制

2.在包含Scaffold页面中监听state,并控制BottomNavigation的可见性。

3.在PageList(也就是Scaffold导航的主页)进入时设置state为true、退出时设置state为false

// ViewModel
class VM: ViewModel() {
private val _state: MutableLiveData<Boolean> = MutableLiveData(true)
val state: LiveData<Boolean> get() = _state
fun setState(status: Boolean) {
_state.postValue(status)
}
} // MainPage
@Compose MainPage(vm: VM) {
LaunchedEffect(key1 = true) {
vm.setState(true)
} DisposableEffect(key1 = true) {
onDispose {
vm.setState(false)
}
}
} // page contains Scaffold
@Composable
fun Greeting(vm: VM) {
// State of BottomNavigation`s visibility
val state = remember { mutableStateOf<Boolean>(true) }
// read the BottomNavigation`s visibility from ViewModel and send to State
vm.state.observeAsState().value?.let { state.value = it } Scaffold(bottomBar = {
// show / hide BottomNavigation controlled by State
state.takeIf { it.value }?.let {
BottomNavigation {
list.forEachIndexed { index, label ->
BottomNavigationItem(
label = { Text(text = label) },
selected = index == selectedItem.value,
onClick = { selectedItem.value = index },
icon = {
Icon(
painter = painterResource(id = R.drawable.ic_launcher_foreground),
contentDescription = null
)
})
}
}
}
}) {
NavHost(navController = navController, startDestination = "one") {
composable(route = "one") { PageList(navController, vm) }
composable(route = "detail") { PageDetail(vm) }
}
}
}

这种做法的好处是简单,侵入性低,无需修改系统api也无需自定义view。缺点就是麻烦,需要在导航中的每个主页都进行设置。


我在StackOverflow上提问时有人回答了另一个办法。这个办法是给每个屏幕添加标志位,来区分是否是导航的主页,之后再创建BottomNavigation时进行判断。贴一下:

You need to specify which screens you want to show and which screens you dont want; Otherwise it will show to all the screens inside Scaffold's body (which you have bottomBar). The code below was from my app.

Create a state which observes any destination changes on the navController

Inside when you can put any screens that you want to show navigationBar else just set currentScreen to NoBottomBar

@Composable
private fun NavController.currentScreen(): State<MainSubScreen> {
val currentScreen = remember { mutableStateOf<MainSubScreen>(MainSubScreen.Home) } DisposableEffect(key1 = this) {
val listener = NavController.OnDestinationChangedListener { _, destination, _ ->
when {
destination.hierarchy.any { it.route == MainSubScreen.Home.route } -> {
currentScreen.value = MainSubScreen.Home
} else -> currentScreen.value = MainSubScreen.NoBottomBar
}
}
addOnDestinationChangedListener(listener)
}
return currentScreen
}

On the Scaffold where you put ur bottomBar

so you can check if currentScreen was NoBottomBar if it was, don't show it

// initialized currentScreeen above
val currentScreen by navController.currentScreen()
Scaffold(
bottomBar = {
if (currentScreen != MainSubScreen.NoBottomBar) {
MainBottomNavigation()
} else Unit
}
) {
// Your screen
}

最新文章

  1. 5.Struts.xml标签中的一些小技巧
  2. hadoop-mongo map/reduce java
  3. 将本地的新建的web Form页面放到服务器提示错误;
  4. 【转载】H264--2--语法及结构
  5. android应用中去掉标题栏的方法
  6. [Eclipse] 详细设置护眼背景色和字体颜色并导出
  7. 【在线】Actionbar Style Generator:ActionBar风格生成器
  8. Camel In Action 阅读笔记 第一部分概述 + 第一章概述 认识Camel
  9. JavaEE系列之(二)commons-fileupload实现文件上传、下载
  10. 关于批处理(bat)数据库备份
  11. amchart
  12. poj3819 Coverage (求直线与圆的交占直线的百分比 )
  13. Linux-ps命令(7)
  14. 腾讯Web工程师的前端书单
  15. VLOOKUP和MATCH嵌套以高效引用多列数据
  16. Java生成名片式的二维码源码分享
  17. hdu6415 记忆化搜索或找规律
  18. 记一次使用getRequestDispatcher遇到的坑。。响应页面出现新建下载任务
  19. python中的全局变量和局部变量
  20. JSP页面用&lt;a&gt;标签访问 Action 出错

热门文章

  1. UIAutomator2 之 计算机积极拒绝
  2. 深度强化学习中稀疏奖励问题Sparse Reward
  3. noip模拟测试22
  4. CentOS 7 安装虚拟机
  5. 洛谷P2962题解
  6. Mybatis源码解析1—— JDBC
  7. C作用域
  8. C++STL——vector类
  9. 十六进制转十进制 BASIC-12
  10. FSM自动售货机 verilog 实现及 code 细节讲解