做主页导航时会用到底部导航栏,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. js排序——sort()排序用法

    sort() 方法用于对数组的元素进行排序,并返回数组.默认排序顺序是根据字符串Unicode码点. 语法:array.sort(fun):参数fun可选.规定排序顺序.必须是函数.注:如果调用该方法 ...

  2. Java集合框架全解

    Collection 集合 集合接口有2个基本方法: public interface Collection<E> { //向集合中添加元素.如果添加元素确实改变了集合就返回 true, ...

  3. ifix与AB PLC contrologix 5300系列的通讯

    在最近一个改造项目中,由于先前的4G 平台不稳定,本公司自己组建4G VPN来实现.遇到问题:AB 高版本PLC(1769-L33ER)使用标签名直接代替了地址,ifix的ABR驱动只支持SLC500 ...

  4. python实现常用五种排序算法

    一.冒泡排序 原理: 比较相邻的元素.如果第一个比第二个大就交换他们两个 每一对相邻元素做同样的工作,直到结尾最后一对 每个元素都重复以上步骤,除了最后一个 第一步: 将乱序中的最大值找出,逐一移到序 ...

  5. 教你如何使用FusionInsight SqoopShell

    摘要:Sqoop-shell是一个Loader的shell工具,其所有功能都是通过执行脚本"sqoop2-shell"来实现的. 本文分享自华为云社区<FusionInsig ...

  6. BUUCTF-[网鼎杯 2018]Fakebook(SSRF+联合注入绕Waf)

    记一道SSRF配合SQL注入的题. 喜欢在做题之前扫一下网站的目录,扫到了robots.txt文件可以访问,拿到user.php.bak的源码.同时还有flag.php. <?php class ...

  7. 控制流程之if判断与while、for循环

    一.if判断 1.什么是if判断? 接收用户输入的名字 接受用户输入的密码 如果用户输入的名字=正确的名字 并且 用户输入的密码=正确的密码 告诉用户登录成功 否则, 告诉用户登录失败 2.为何要有i ...

  8. C++STL—string类

    string容器 1.1 string容器的基本概念 string容器是一个类 这个容器中有一个指针,指针维护了一个数组 string容器提供copy.find.insert.replace等等功能 ...

  9. Anaconda创建虚拟环境并使用Jupyter-notebook打开虚拟环境

    由于需要使用Tensorflow的1.xx的低版本,但是cmd下载一直报错没有解决,就想着用Anaconda,但是真实环境我已经装上Tensorflow2.0了不想换了,所以就想着再建一个python ...

  10. LiteFlow 2.6.0版本发行注记,项目逻辑解耦的利器

    前言 自从LiteFlow 2.5.X版本发布依赖,陆续经历了10个小版本的迭代.社区群也稳固增长,每天都有很多小伙伴在问我问题. 但是我发现最多人问我的还是:什么时候能支持界面编排? 从LiteFL ...