做主页导航时会用到底部导航栏,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
}

Jetpack Compose之隐藏Scaffold的BottomNavigation的更多相关文章

  1. Jetpack Compose学习(7)——MD样式架构组件Scaffold及导航底部菜单

    Jetpack Compose学习(7)--MD样式架构组件Scaffold及导航底部菜单 | Stars-One的杂货小窝 Compose给我们提供了一个Material Design样式的首页组件 ...

  2. Jetpack Compose What and Why, 6个问题

    Jetpack Compose What and Why, 6个问题 1.这个技术出现的背景, 初衷, 要达到什么样的目标或是要解决什么样的问题. Jetpack Compose是什么? 它是一个声明 ...

  3. Jetpack Compose学习(3)——图标(Icon) 按钮(Button) 输入框(TextField) 的使用

    原文地址: Jetpack Compose学习(3)--图标(Icon) 按钮(Button) 输入框(TextField) 的使用 | Stars-One的杂货小窝 本篇分别对常用的组件:图标(Ic ...

  4. Jetpack Compose学习(5)——从登录页美化开始学习布局组件使用

    原文:Jetpack Compose学习(5)--从登录页美化开始学习布局组件使用 | Stars-One的杂货小窝 本篇主要讲解常用的布局,会与原生Android的布局控件进行对比说明,请确保了解A ...

  5. Jetpack Compose学习(6)——关于Modifier的妙用

    原文: Jetpack Compose学习(6)--关于Modifier的妙用 | Stars-One的杂货小窝 之前学习记录中也是陆陆续续地将常用的Modifier的方法穿插进去了,本期就来详细的讲 ...

  6. Jetpack Compose和View的互操作性

    Jetpack Compose Interoperability Compose风这么大, 对于已有项目使用新技术, 难免会担心兼容性. 对于Compose来说, 至少和View的结合是无缝的. (目 ...

  7. Jetpack Compose学习(1)——从登录页开始入门

    原文地址:Jetpack Compose学习(1)--从登录页开始入门 | Stars-One的杂货小窝 Jetpack Compose UI在前几天出了1.0正式版,之前一直还在观望,终于是出了正式 ...

  8. Jetpack Compose 1.0 终于要投入使用了!

    前言 Jetpack Compose 是用于构建原生界面的「新款 Android 工具包」.2021 Google IO 大会上,Google宣布:「Jetpack Compose 1.0 即将面世」 ...

  9. Android Kotlin Jetpack Compose UI框架 完全解析

    前言 Q1的时候公司列了个培训计划,部分人作为讲师要上报培训课题.那时候刚从好几个Android项目里抽离出来,正好看到Jetpack发布了新玩意儿--Compose,我被它的快速实时打包给吸引住了, ...

随机推荐

  1. Cesium产品体系

    Cesium是国外Analytical Graphics, Inc.公司开发的一款基于JavaScript 的使用WebGL的地图引擎.Cesium支持3D,2D,2.5D形式的地图展示,可以自行绘制 ...

  2. Select、Poll、Epoll IO复用技术

    简介 目前多进程方式实现的服务器端,一次创建多个工作子进程来给客户端提供服务, 但是创建进程会耗费大量资源,导致系统资源不足 IO复用技术就是让一个进程同时为多个客户端端提供服务 IO复用技术 之 S ...

  3. element UI表格行高、padding等设置报错问题

    element UI里面表格的行高需要自己调整高度和设置padding,直接写style是不行的,里面有 : 1.row-style (行的 style) 2.header-row-styl   (表 ...

  4. etcd学习(5)-etcd的Raft一致性算法原理

    ETCD的Raft一致性算法原理 前言 Raft原理了解 raft选举 raft中的几种状态 任期 leader选举 日志复制 安全性 leader宕机,新的leader未同步前任committed的 ...

  5. 论文笔记:(ICML2020)On Learning Sets of Symmetric Elements

    目录 摘要 一.引言 二.先前的工作 三.基础 3.1 符号和基本定义 3.2 G-不变网络 3.3 描述等变层 3.4 Deep sets 四.DSS层 4.1 对称元素集合 4.2 等变层的表征 ...

  6. 自学linux——11.shell入门

    shell 基础 1.shell介绍(内置脚本) 程序开发的效率非常高,依赖于功能强大的命令可以迅速地完成开发任务(批处理) 语法简单,代码写起来比较轻松,简单易学 (1)什么是shell shell ...

  7. CF559B Equivalent Strings TJ

    前言 题目传送门 正解:模拟,递归. 考试的 T4,还是想复杂了 qwq. 这题不要用 STL,容易 \(\texttt{TLE}\)!! 题意简述 翻译够简了. 对了给一下样例解释的翻译: 第一个样 ...

  8. OSPF多区域

    目录 一.OSPF的多区域 1.1 生成OSPF多区域的原因 1.2 路由器的类型 1.3 区域的类型 二.链路状态数据库 2.1 链路状态数据库的组成 2.2链路状态通告 三.OSPF多区域配置 四 ...

  9. Vulhub-DC-3靶场

    Vulhub-DC-3靶场 前言 今天把DC-3的靶场打了一遍,可以说这个靶场用到的思路是非常经典的,从信息搜集到漏洞利用包括内核提权.最最重要的是为了下载它的提权EXP,我它喵还花了一块二买了个CS ...

  10. Groovy正则表达式复杂逻辑判断实例

    下面的两个pattern(p1和p2)分别代表了(A or B) and (C or D)和(A and B) or (C and D)的跨行匹配结果,当然还可以用正则表达式构建更复杂的pattern ...