在导航组件中隐藏工具栏或底部导航栏

16

我遵循了来自Android开发者指南的指导,并将导航组件实现到我的应用程序中。 当我需要一些屏幕有或没有工具栏/底部导航栏时,我遇到了一个问题。

Android开发者的示例布局

  <androidx.appcompat.widget.Toolbar
        .../>

    <fragment
        android:id="@+id/nav_host_fragment"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"

        app:defaultNavHost="true"
        app:navGraph="@navigation/nav_graph" />

    <com.google.android.material.bottomnavigation.BottomNavigationView
        .../>

强制我在MainActivity的OnDestinationChanged回调中隐藏/显示工具栏和底部导航栏:

Translated:

Forces me to hide/show toolbar/bottomNavBar in OnDestinationChanged callback in MainActivity:

navController.addOnDestinationChangedListener { _, destination, _ ->
                when (destination) {
                    R.id.topLevelDestination-> {
                        toolbar.visibility = View.GONE
                        bottomNav.visibility = View.VISIBLE
                    }
                    R.id.lowLevelDestination -> {
                        toolbar.visibility = View.VISIBLE
                        bottomNav.visibility = View.GONE
                    }

当然,如果我这样做,我在看到新的片段之前就会调整我的布局。我的意思是,在片段A上看到底部导航栏消失,在片段A仍然在屏幕上时,在底部导航栏所在的位置看到片段B的部分,之后片段B出现。

如何解决?我需要嵌套导航图吗?


更新:添加了问题的gif动画

enter image description here

视频描述:这是我屏幕的一部分。您可以在视频中看到系统UI、底部导航栏和带有按钮的主要片段。当我点击按钮时,导航图将我导航到一个没有底部导航栏的目标。因此,当OnDestinationChanged时,我执行bottomNavBar.hide()。正如您所看到的,bottomNavBar在我实际导航之前就已经消失了,并且您可以看到底部导航栏消失后我的目标片段的部分可见。这就是问题所在。


1
你可以在每个片段的 onStart() 中隐藏/显示工具栏,而不是依赖于 addOnDestinationChangedListener。你考虑过这种方法吗? - azizbekian
@azizbekian 是的,我已经这样做了。效果一样。我的问题是,在 mainactivity_layout 中有 1 个 fragment 容器用于所有片段,无论是否带有工具栏和底部栏。 - StayCool
@StayCool 如果Luis的答案解决了你的问题,那就太好了。除了视频之外,你也可以在stackoverflow上放置一个最大为2mb的gif图像。当UI需要动态状态时,我开始使用gif,你可以使用网站将约20秒的视频转换为gif。我仍然不明白如果你有一个NavigationHost或多个NavigationHost,它如何与ViewModel有关系,这里的重点是你可以在Fragment的生命周期中设置LiveData并观察任何你可以访问到该ViewModel的地方的更改。 - Thracian
@Thracian 我在一个问题中添加了一个gif,请看一下。 - StayCool
@Luis Villabolos不,那不是真的。请记住,当我改变目标导航控制器时,只有主题开始中间部分的XML会发生变化。然后我在OnDestinationChangedCallback中隐藏bottomNavigationBar和Toolbar。这就是导致故障的原因。因为这两个过程不同步,无法同步。我看到的唯一方法是使每个屏幕的root_layout不同(有或没有底部栏和工具栏)。 - StayCool
显示剩余6条评论
1个回答

4

我陷入了这个问题两天,但是通过使用XML,您可以解决您的问题。

  1. 您需要将工具栏包装在CoordinatorLayout中
  2. 您的工具栏需要scroll和enter滚动标志
  3. 您需要将片段放入另一个布局中,并在layout_behavior中放置特定行为:@string/appbar_scrolling_view_behavior
  4. 在您的BottomNavigationView中放置谷歌行为:com.google.android.material.behavior.HideBottomViewOnScrollBehavior

就像这样:

<androidx.coordinatorlayout.widget.CoordinatorLayout
    ...>

    <com.google.android.material.appbar.AppBarLayout
        android:id="@+id/appBar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">

        <androidx.appcompat.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            app:layout_scrollFlags="scroll|enterAlways"
            app:popupTheme="@style/ThemeOverlay.AppCompat.ActionBar" />

    </com.google.android.material.appbar.AppBarLayout>

    <androidx.core.widget.NestedScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">

        <fragment
            android:id="@+id/fragment_host"
            android:name="androidx.navigation.fragment.NavHostFragment"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:defaultNavHost="true"
            app:navGraph="@navigation/graph_main" />
    </androidx.core.widget.NestedScrollView>

    <com.google.android.material.bottomnavigation.BottomNavigationView
        android:id="@+id/bottom"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_gravity="bottom"
        android:layout_marginStart="0dp"
        android:layout_marginEnd="0dp"
        android:background="?android:attr/windowBackground"
        app:labelVisibilityMode="unlabeled"
        app:layout_behavior="com.google.android.material.behavior.HideBottomViewOnScrollBehavior"
        app:menu="@menu/menu_main" />

</androidx.coordinatorlayout.widget.CoordinatorLayout>

顺便说一下,我添加了一个NestedScrollView,以使得所有的片段都可以滚动,并且在需要时节省其他布局。


那么,所有这些如何协同工作呢?我不知道这怎么可能是一个解决方案。 - StayCool
对我来说,这个解决方案似乎可以工作,但有一个主要缺点...我在片段中有一个回收视图,所以它会在滚动视图中扩展片段->生成许多不可见的回收视图,这对性能很不好... - benjiii

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