隐藏Android底部导航栏以供子屏幕/片段使用

22

我正在尝试创建一个单activity的Android应用程序。 我有一个带有BottomNavigationView的MainActivity(唯一的activity),三个顶级fragment和一些子fragment。我的要求是,每当屏幕显示顶级fragment时,底部导航应该可见,以便可以进行切换。但当我查看任何子fragment时,底部导航应该隐藏。是否有使用Navigation组件的开箱即用方式,或者需要手动更改可见性?

6个回答

34

更新(导航组件1.0)

导航组件1.0.0-alpha08版本开始,方法addOnNavigatedListener(controller: NavController, destination: NavDestination)已更改为addOnDestinationChangedListener(controller: NavController, destination: NavDestination, arguments: Bundle)。其行为也略有改变(如果目标的参数发生更改,它也会被调用)。

旧答案

您可以使用NavController.OnNavigatedListener来实现此行为(在Activity onCreate中设置它):

findNavController(R.id.container).addOnNavigatedListener { _, destination ->
    when (destination.id) {
        R.id.dashboardFragment -> showBottomNavigation()
        else -> hideBottomNavigation()
    }
}

private fun hideBottomNavigation() {
    // bottom_navigation is BottomNavigationView
    with(bottom_navigation) {
        if (visibility == View.VISIBLE && alpha == 1f) {
            animate()
                    .alpha(0f)
                    .withEndAction { visibility = View.GONE }
                    .duration = EXIT_DURATION
        }
    }
}

private fun showBottomNavigation() {
    // bottom_navigation is BottomNavigationView
    with(bottom_navigation) {
        visibility = View.VISIBLE
        animate()
                .alpha(1f)
                .duration = ENTER_DURATION
    }
}

1
使用 addOnNavigatedListener 仍然可行吗?当我尝试使用它时,会得到一个未解决的引用错误。 - IainCunningham
2
addOnNavigatedListener is changed to addOnDestinationChangedListener - Kalyan Dechiraju
EXIT_DURATIONENTER_DURATION定义在哪里? - A1m
@A1m 你可以在任何地方定义它们,这些只是以毫秒为单位的常量。 - theme_an
但是如何让它们匹配,以便BottomNavigation始终与Fragments对齐呢?如果没有这样做,有时您会看到片段出现延迟,但栏稍后出现,或者反之亦然。 - A1m
1
@A1m 是的,这个解决方案确实存在这样的问题,但它是在FragmentLifecycleCallbacks出现之前编写的。我建议您尝试Hicham的解决方案,以获得更好的动画协调。 - theme_an

7
使用addOnDestinationChangedListener可以解决问题,这也是官方文档推荐的解决方案,但会导致一些闪烁,因为在片段附加之前就执行了回调。
我发现以下答案更灵活,处理动画更好:
supportFragmentManager.registerFragmentLifecycleCallbacks(object : FragmentManager.FragmentLifecycleCallbacks() {
        override fun onFragmentViewCreated(fm: FragmentManager, f: Fragment, v: View, savedInstanceState: Bundle?) {
            TransitionManager.beginDelayedTransition(binding.root, Slide(Gravity.BOTTOM).excludeTarget(R.id.nav_host_fragment, true))
            when (f) {
                is ModalFragment -> {
                    binding.bottomNavigation.visibility = View.GONE
                }
                else -> {
                    binding.bottomNavigation.visibility = View.VISIBLE
                }
            }
        }
    }, true)

你可以根据片段之间的转换自定义它,通过选择不同的动画效果(例如我的示例中使用的是Slide),或在另一个生命周期回调中进行调用。


如何在导航组件中使用这个? - Andrew
这不依赖于导航组件,只依赖于片段管理器。 - Hicham
我已经解决了我的问题。我在我的onCreateView中改变了可见性,并在我的主Fragment中再次改变了可见性。这比你的方法更好,没有任何闪烁等问题。 - Andrew
1
我认为@Hicham的答案很好,可以防止闪烁。 - 11m0

4

你需要在 MainActivity 中创建一个可见性方法,并在需要显示或隐藏的片段中调用该方法。

我在这种情况下遇到的一个问题是,底部导航条的可见性并没有被正确地去除。因此,我将底部导航视图放置在相对布局中,并隐藏了该父视图。


3

您只需在 MainActivity 中编写此代码即可。

class MainActivity : AppCompatActivity() {

    private lateinit var navController: NavController

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)


        //Getting the Navigation Controller
        navController = Navigation.findNavController(this, R.id.fragment)

        //Setting the navigation controller to Bottom Nav
        bottomNav.setupWithNavController(navController)


        //Setting up the action bar
        NavigationUI.setupActionBarWithNavController(this, navController)

        //setting the Bottom navigation visibiliy
        navController.addOnDestinationChangedListener { _, destination, _ ->

           if(destination.id == R.id.full_screen_destination ){
               bottomNav.visibility = View.GONE
           }else{
               bottomNav.visibility = View.VISIBLE
           }


        }

    }

请参考 Android 开发者文档以获取更多详细信息: 使用 NavigationUI 更新 UI 组件


0
navController.addOnDestinationChangedListener { _, destination, _ ->
    val isMainPage = bottomNavigationView.selectedItemId == destination.id
    bottomNavigationView.isVisible = isMainPage
}

0

所以即使这个问题已经被回答并且接受的答案是可行的,这里是实现此行为的代码:

MainActivity

fun hideBottomNav() {
   bottomNavigationView.visibility = View.GONE
}
    
fun showBottomNav() {
    bottomNavigationView.visibility = View.VISIBLE
}

然后在你的片段中调用函数 onViewCreated()onDetach() 函数,例如:

片段

class FragmentWithOutBottomNav() : Fragment() {
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        (activity as MainActivity).hideBottomNav()
    }

    override fun onDetach() {
        super.onDetach()
        (activity as MainActivity).showBottomNav()
    }
}

希望我能帮助到一些人。祝编码愉快!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接