当导航到可组合时,我们如何隐藏 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 值并设置enterexit 动画,在我的例子中,我使用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(包含导航)?的主要内容,如果未能解决你的问题,请参考以下文章

当用户快速滚动表格视图时如何隐藏和取消隐藏导航栏?

如何在更改uiview的隐藏模式时添加动画?

如何在 iOS 13 上最初隐藏导航控制器中的搜索栏?

iOS 7隐藏导航栏时如何更改状态栏的颜色?

如何根据某人是不是使用 AngularJS 登录来隐藏和显示导航栏元素?

滚动时隐藏状态栏