当导航到可组合时,我们如何隐藏 BottomAppBar(包含导航)?
Posted
技术标签:
【中文标题】当导航到可组合时,我们如何隐藏 BottomAppBar(包含导航)?【英文标题】:How can we hide BottomAppBar (with navigation include) when navigate to composable? 【发布时间】:2021-08-07 01:38:14 【问题描述】:我有问题。
问题是当我导航到“添加问题”屏幕时,我不知道如何隐藏底部应用栏。
我需要你的帮助。
这是带有底部应用栏的 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)
我认为问题是因为这就像活动和片段,我有一个可组合屏幕所在的盒子,我所有的页面都在他里面。
【问题讨论】:
【参考方案1】:我建议您将AnimatedVisibility
用于BottomNavigation
小部件,我认为这是最清晰的撰写方式。
-
你应该使用
remeberSaveable
来存储BottomBar的状态:
// State of bottomBar, set state to false, if current page route is "car_details"
val bottomBarState = rememberSaveable (mutableStateOf(true))
-
在composable函数中,我们使用
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
动画和@98765434 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
【讨论】:
很好。我尝试过类似地实现它(使用 OnDestinationChangedListener 的 DisposableEffect),但 BottomBar 根本没有动画。有什么想法吗? @bompf 您是否尝试更改 OnDestinationChangedListener 中的 BottomBarState 值? 我的错误。我用if (isVisible) ...
包裹了AnimatedVisibility。现在可以了。
@AndreiR,根据您的解决方案,您将 navController 传递给每个可用于导航到其他可组合物的可组合物。如果车载屏幕有更多的按钮和可点击的组合,那不会造成混乱吗?在这种情况下,可组合项可能会被分成单独的文件夹和包。并且将 navController 传递给它们中的每一个肯定会造成混乱,对吧?
@FahimHoque,就我而言,我使用简单的导航方式。关于复杂的案件 - 你是对的。如果你有很多路线,我推荐阅读这篇关于导航的文章medium.com/google-developer-experts/…。在文章末尾,您可以阅读组织导航的不同解决方案。【参考方案2】:
如果您想隐藏BottomBar
,请不要输出它。
类似:
Scaffold(
bottomBar =
if (currentRoute != "xxxx")
BottomAppBar()
//....
,
currentRoute
在哪里(至少使用 Navigation Compose 2.4.0-alpha01):
val navBackStackEntry by navController.currentBackStackEntryAsState()
val currentRoute = navBackStackEntry.destination.route
【讨论】:
哦...好吧,但是什么是 currentRoute ?因为我做了这个:val currentRoute = navController.currentBackStackEntry?.arguments?.getString(KEY_ROUTE),但它没有用 @Mehdi.ncb 我已经更新了答案。查看官方文档:developer.android.com/jetpack/compose/navigation#bottom-nav 你回答了,但是,这是最好的方法吗?就像,当我回去时,我看到我的底部导航栏从底部出现(小动画 - 0.2 秒)。那么,您对此有最佳选择吗? @Mehdi.ncb 老实说,我不知道是否有更好的选择,但我认为使用当前的 API 是正确的方法。 好的,非常感谢,您在 *** 上帮助了很多人以上是关于当导航到可组合时,我们如何隐藏 BottomAppBar(包含导航)?的主要内容,如果未能解决你的问题,请参考以下文章