导航到可组合项时,我们如何隐藏 BottomAppBar(包含导航)?
How can we hide BottomAppBar (with navigation include) when navigate to composable?
我有问题。
问题是当我导航到“添加问题”屏幕时,我不知道如何隐藏底部应用栏。
我需要你的帮助。
这是带有底部应用栏的 MyScreen
@Composable
fun Navigation() {
val navController = rememberNavController()
val items = listOf(Screen.Home, Screen.Search, Screen.Notifications, Screen.Profil)
Scaffold(
bottomBar = {
bottomAppNavigation(navController = navController, items)
}
) {
Box(modifier = Modifier.padding(it)) {
ScreenController(navController = navController)
}
}
}
这是我的带有 navHost 的控制器
@ExperimentalComposeUiApi
@Composable
fun ScreenController(navController: NavHostController) {
NavHost(navController = navController, startDestination = Screen.Home.route) {
composable(Screen.Home.route) {
HomeScreen(navController)
}
composable(Screen.Search.route) {
SearchScreen(navController, it)
}
composable(Screen.Notifications.route) {
}
composable(Screen.Profil.route) {
user_profil()
}
composable("Ask_question") {
AskScreen(navController)
}
}
}
这个问题我认为是因为这就像 activity 和 fragment,我有一个盒子,可组合屏幕所在的地方,我所有的页面都在他里面。
如果你想隐藏 BottomBar
就不要输出它。
类似于:
Scaffold(
bottomBar = {
if (currentRoute != "xxxx") {
BottomAppBar() {
//....
}
}
},
currentRoute
所在的位置(至少使用 Navigation Compose 2.4.0-alpha01):
val navBackStackEntry by navController.currentBackStackEntryAsState()
val currentRoute = navBackStackEntry.destination.route
我建议您将 AnimatedVisibility
用于 BottomNavigation
小部件,我认为这是最清晰的撰写方式。
- 您应该使用
remeberSaveable
来存储 BottomBar 的状态:
// State of bottomBar, set state to false, if current page route is "car_details"
val bottomBarState = rememberSaveable { (mutableStateOf(true)) }
- 在可组合函数中我们使用
when
来控制BottomBar的状态,下面我们设置bottomBarState
到true
,如果我们想显示BottomBar,否则我们设置bottomBarState
到 false
:
val navController = rememberNavController()
// Subscribe to navBackStackEntry, required to get current route
val navBackStackEntry by navController.currentBackStackEntryAsState()
// Control BottomBar
when (navBackStackEntry?.destination?.route) {
"cars" -> {
// Show BottomBar
bottomBarState.value = true
}
"bikes" -> {
// Show BottomBar
bottomBarState.value = true
}
"settings" -> {
// Show BottomBar
bottomBarState.value = true
}
"car_details" -> {
// Hide BottomBar
bottomBarState.value = false
}
}
Scaffold(
bottomBar = {
BottomBar(
navController = navController,
bottomBarState = bottomBarState
)
},
content = {
NavHost(
navController = navController,
startDestination = NavigationItem.Cars.route,
) {
composable(NavigationItem.Cars.route) {
CarsScreen(
navController = navController,
)
}
composable(NavigationItem.Bikes.route) {
BikesScreen(
navController = navController
)
}
composable(NavigationItem.Settings.route) {
SettingsScreen(
navController = navController,
)
}
composable(NavigationItem.CarDetails.route) {
CarDetailsScreen(
navController = navController,
)
}
}
}
)
- 将
BottomNavigation
放入AnimatedVisibility
,设置bottomBarState
的visible
值并设置enter
和exit
动画,在我的例子中我使用 slideInVertically
制作 enter
动画,使用 slideOutVertically
制作 exit
动画:
AnimatedVisibility(
visible = bottomBarState.value,
enter = slideInVertically(initialOffsetY = { it }),
exit = slideOutVertically(targetOffsetY = { it }),
content = {
BottomNavigation {
val navBackStackEntry by navController.currentBackStackEntryAsState()
val currentRoute = navBackStackEntry?.destination?.route
items.forEach { item ->
BottomNavigationItem(
icon = {
Icon(
painter = painterResource(id = item.icon),
contentDescription = item.title
)
},
label = { Text(text = item.title) },
selected = currentRoute == item.route,
onClick = {
navController.navigate(item.route) {
popUpTo(navController.graph.findStartDestination().id) {
saveState = true
}
launchSingleTop = true
restoreState = true
}
}
)
}
}
}
)
MainActivity 的完整代码:
package codes.andreirozov.bottombaranimation
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.ExperimentalAnimationApi
import androidx.compose.animation.slideInVertically
import androidx.compose.animation.slideOutVertically
import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.res.painterResource
import androidx.navigation.NavController
import androidx.navigation.NavGraph.Companion.findStartDestination
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.currentBackStackEntryAsState
import androidx.navigation.compose.rememberNavController
import codes.andreirozov.bottombaranimation.screens.BikesScreen
import codes.andreirozov.bottombaranimation.screens.CarDetailsScreen
import codes.andreirozov.bottombaranimation.screens.CarsScreen
import codes.andreirozov.bottombaranimation.screens.SettingsScreen
import codes.andreirozov.bottombaranimation.ui.theme.BottomBarAnimationTheme
@ExperimentalAnimationApi
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
BottomBarAnimationApp()
}
}
}
@ExperimentalAnimationApi
@Composable
fun BottomBarAnimationApp() {
// State of bottomBar, set state to false, if current page route is "car_details"
val bottomBarState = rememberSaveable { (mutableStateOf(true)) }
BottomBarAnimationTheme {
val navController = rememberNavController()
// Subscribe to navBackStackEntry, required to get current route
val navBackStackEntry by navController.currentBackStackEntryAsState()
// Control BottomBar
when (navBackStackEntry?.destination?.route) {
"cars" -> {
// Show BottomBar
bottomBarState.value = true
}
"bikes" -> {
// Show BottomBar
bottomBarState.value = true
}
"settings" -> {
// Show BottomBar
bottomBarState.value = true
}
"car_details" -> {
// Hide BottomBar
bottomBarState.value = false
}
}
Scaffold(
bottomBar = {
BottomBar(
navController = navController,
bottomBarState = bottomBarState
)
},
content = {
NavHost(
navController = navController,
startDestination = NavigationItem.Cars.route,
) {
composable(NavigationItem.Cars.route) {
CarsScreen(
navController = navController,
)
}
composable(NavigationItem.Bikes.route) {
BikesScreen(
navController = navController
)
}
composable(NavigationItem.Settings.route) {
SettingsScreen(
navController = navController,
)
}
composable(NavigationItem.CarDetails.route) {
CarDetailsScreen(
navController = navController,
)
}
}
}
)
}
}
@ExperimentalAnimationApi
@Composable
fun BottomBar(navController: NavController, bottomBarState: MutableState<Boolean>) {
val items = listOf(
NavigationItem.Cars,
NavigationItem.Bikes,
NavigationItem.Settings
)
AnimatedVisibility(
visible = bottomBarState.value,
enter = slideInVertically(initialOffsetY = { it }),
exit = slideOutVertically(targetOffsetY = { it }),
content = {
BottomNavigation {
val navBackStackEntry by navController.currentBackStackEntryAsState()
val currentRoute = navBackStackEntry?.destination?.route
items.forEach { item ->
BottomNavigationItem(
icon = {
Icon(
painter = painterResource(id = item.icon),
contentDescription = item.title
)
},
label = { Text(text = item.title) },
selected = currentRoute == item.route,
onClick = {
navController.navigate(item.route) {
popUpTo(navController.graph.findStartDestination().id) {
saveState = true
}
launchSingleTop = true
restoreState = true
}
}
)
}
}
}
)
}
结果:
不要忘记对组合函数使用 @ExperimentalAnimationApi
注释。
更新: Compose 版本 1.1.0 及更高版本 @ExperimentalAnimationApi
不需要。
22.02.2022更新:我做了一些研究,更新了点2。现在我们用when
来控制bottomBarState
.
gitHub 上提供完整代码:
https://github.com/AndreiRoze/BottomBarAnimation
官方文档中可用的动画示例:
https://developer.android.com/jetpack/compose/animation
我有问题。
问题是当我导航到“添加问题”屏幕时,我不知道如何隐藏底部应用栏。
我需要你的帮助。
这是带有底部应用栏的 MyScreen
@Composable
fun Navigation() {
val navController = rememberNavController()
val items = listOf(Screen.Home, Screen.Search, Screen.Notifications, Screen.Profil)
Scaffold(
bottomBar = {
bottomAppNavigation(navController = navController, items)
}
) {
Box(modifier = Modifier.padding(it)) {
ScreenController(navController = navController)
}
}
}
这是我的带有 navHost 的控制器
@ExperimentalComposeUiApi
@Composable
fun ScreenController(navController: NavHostController) {
NavHost(navController = navController, startDestination = Screen.Home.route) {
composable(Screen.Home.route) {
HomeScreen(navController)
}
composable(Screen.Search.route) {
SearchScreen(navController, it)
}
composable(Screen.Notifications.route) {
}
composable(Screen.Profil.route) {
user_profil()
}
composable("Ask_question") {
AskScreen(navController)
}
}
}
这个问题我认为是因为这就像 activity 和 fragment,我有一个盒子,可组合屏幕所在的地方,我所有的页面都在他里面。
如果你想隐藏 BottomBar
就不要输出它。
类似于:
Scaffold(
bottomBar = {
if (currentRoute != "xxxx") {
BottomAppBar() {
//....
}
}
},
currentRoute
所在的位置(至少使用 Navigation Compose 2.4.0-alpha01):
val navBackStackEntry by navController.currentBackStackEntryAsState()
val currentRoute = navBackStackEntry.destination.route
我建议您将 AnimatedVisibility
用于 BottomNavigation
小部件,我认为这是最清晰的撰写方式。
- 您应该使用
remeberSaveable
来存储 BottomBar 的状态:
// State of bottomBar, set state to false, if current page route is "car_details"
val bottomBarState = rememberSaveable { (mutableStateOf(true)) }
- 在可组合函数中我们使用
when
来控制BottomBar的状态,下面我们设置bottomBarState
到true
,如果我们想显示BottomBar,否则我们设置bottomBarState
到false
:
val navController = rememberNavController()
// Subscribe to navBackStackEntry, required to get current route
val navBackStackEntry by navController.currentBackStackEntryAsState()
// Control BottomBar
when (navBackStackEntry?.destination?.route) {
"cars" -> {
// Show BottomBar
bottomBarState.value = true
}
"bikes" -> {
// Show BottomBar
bottomBarState.value = true
}
"settings" -> {
// Show BottomBar
bottomBarState.value = true
}
"car_details" -> {
// Hide BottomBar
bottomBarState.value = false
}
}
Scaffold(
bottomBar = {
BottomBar(
navController = navController,
bottomBarState = bottomBarState
)
},
content = {
NavHost(
navController = navController,
startDestination = NavigationItem.Cars.route,
) {
composable(NavigationItem.Cars.route) {
CarsScreen(
navController = navController,
)
}
composable(NavigationItem.Bikes.route) {
BikesScreen(
navController = navController
)
}
composable(NavigationItem.Settings.route) {
SettingsScreen(
navController = navController,
)
}
composable(NavigationItem.CarDetails.route) {
CarDetailsScreen(
navController = navController,
)
}
}
}
)
- 将
BottomNavigation
放入AnimatedVisibility
,设置bottomBarState
的visible
值并设置enter
和exit
动画,在我的例子中我使用slideInVertically
制作enter
动画,使用slideOutVertically
制作exit
动画:
AnimatedVisibility(
visible = bottomBarState.value,
enter = slideInVertically(initialOffsetY = { it }),
exit = slideOutVertically(targetOffsetY = { it }),
content = {
BottomNavigation {
val navBackStackEntry by navController.currentBackStackEntryAsState()
val currentRoute = navBackStackEntry?.destination?.route
items.forEach { item ->
BottomNavigationItem(
icon = {
Icon(
painter = painterResource(id = item.icon),
contentDescription = item.title
)
},
label = { Text(text = item.title) },
selected = currentRoute == item.route,
onClick = {
navController.navigate(item.route) {
popUpTo(navController.graph.findStartDestination().id) {
saveState = true
}
launchSingleTop = true
restoreState = true
}
}
)
}
}
}
)
MainActivity 的完整代码:
package codes.andreirozov.bottombaranimation
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.ExperimentalAnimationApi
import androidx.compose.animation.slideInVertically
import androidx.compose.animation.slideOutVertically
import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.res.painterResource
import androidx.navigation.NavController
import androidx.navigation.NavGraph.Companion.findStartDestination
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.currentBackStackEntryAsState
import androidx.navigation.compose.rememberNavController
import codes.andreirozov.bottombaranimation.screens.BikesScreen
import codes.andreirozov.bottombaranimation.screens.CarDetailsScreen
import codes.andreirozov.bottombaranimation.screens.CarsScreen
import codes.andreirozov.bottombaranimation.screens.SettingsScreen
import codes.andreirozov.bottombaranimation.ui.theme.BottomBarAnimationTheme
@ExperimentalAnimationApi
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
BottomBarAnimationApp()
}
}
}
@ExperimentalAnimationApi
@Composable
fun BottomBarAnimationApp() {
// State of bottomBar, set state to false, if current page route is "car_details"
val bottomBarState = rememberSaveable { (mutableStateOf(true)) }
BottomBarAnimationTheme {
val navController = rememberNavController()
// Subscribe to navBackStackEntry, required to get current route
val navBackStackEntry by navController.currentBackStackEntryAsState()
// Control BottomBar
when (navBackStackEntry?.destination?.route) {
"cars" -> {
// Show BottomBar
bottomBarState.value = true
}
"bikes" -> {
// Show BottomBar
bottomBarState.value = true
}
"settings" -> {
// Show BottomBar
bottomBarState.value = true
}
"car_details" -> {
// Hide BottomBar
bottomBarState.value = false
}
}
Scaffold(
bottomBar = {
BottomBar(
navController = navController,
bottomBarState = bottomBarState
)
},
content = {
NavHost(
navController = navController,
startDestination = NavigationItem.Cars.route,
) {
composable(NavigationItem.Cars.route) {
CarsScreen(
navController = navController,
)
}
composable(NavigationItem.Bikes.route) {
BikesScreen(
navController = navController
)
}
composable(NavigationItem.Settings.route) {
SettingsScreen(
navController = navController,
)
}
composable(NavigationItem.CarDetails.route) {
CarDetailsScreen(
navController = navController,
)
}
}
}
)
}
}
@ExperimentalAnimationApi
@Composable
fun BottomBar(navController: NavController, bottomBarState: MutableState<Boolean>) {
val items = listOf(
NavigationItem.Cars,
NavigationItem.Bikes,
NavigationItem.Settings
)
AnimatedVisibility(
visible = bottomBarState.value,
enter = slideInVertically(initialOffsetY = { it }),
exit = slideOutVertically(targetOffsetY = { it }),
content = {
BottomNavigation {
val navBackStackEntry by navController.currentBackStackEntryAsState()
val currentRoute = navBackStackEntry?.destination?.route
items.forEach { item ->
BottomNavigationItem(
icon = {
Icon(
painter = painterResource(id = item.icon),
contentDescription = item.title
)
},
label = { Text(text = item.title) },
selected = currentRoute == item.route,
onClick = {
navController.navigate(item.route) {
popUpTo(navController.graph.findStartDestination().id) {
saveState = true
}
launchSingleTop = true
restoreState = true
}
}
)
}
}
}
)
}
结果:
不要忘记对组合函数使用 @ExperimentalAnimationApi
注释。
更新: Compose 版本 1.1.0 及更高版本 @ExperimentalAnimationApi
不需要。
22.02.2022更新:我做了一些研究,更新了点2。现在我们用when
来控制bottomBarState
.
gitHub 上提供完整代码: https://github.com/AndreiRoze/BottomBarAnimation
官方文档中可用的动画示例: https://developer.android.com/jetpack/compose/animation