Hiding toolbar or bottomNavigationBar in Navigation Component
Asked Answered
G

1

17

I followed guide from android.developers and implemented a navigation component into my app. I stumbled across a problem when I need some screens to be with or without a toolbar/bottom navbar.

Android developers example's layout

  <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
        .../>

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
                    }

And, of course, if I do it like this I have my layout resize before I see new fragment. I mean I see how bottom nav disappears on fragment A, and I see fragment's B parts in the place where bottomNavBar was when fragment A is still on the screen, and after that fragment, B appears.

How to solve it? Do I need nested nav graphs?


update: Added a gif of problem

enter image description here

Video description: it's a cutted part of my screen. On video you can see system UI, bottom nav bar and main fragment with a button. When i click button nav graph navigates me to a destination without bottom navigation bar. So, I do bottomNavBar.hide() when OnDestinationChanged. As you can see, bottomNavBar is disappeared BEFORE I actually navigate and you can see part of my destination fragment visible after bottomnavBar gone. That's the problem.

Glasper answered 18/6, 2020 at 11:26 Comment(11)
Instead of relying on addOnDestinationChangedListener you can hide/show toolbar from each fragment's onStart(). Have you considered this approach?Sickle
@Sickle yes, I did that. Same effect. My problem is that I have 1 fragment container in mainactivity_layout for all fragments, with or without toolbar and bottom bar.Glasper
You can use a shared ViewModel between fragments and activity with only oneMutableLiveData<Boolean> to set visibility of Toolbar, and set it in appropriate lifecycle method of the fragments, onCreateView, onViewCreated, onStart or onResumeQuiescent
@Quiescent actually, I already know the answer to a question. It's a nested nav component graphs. It's when you have one root_fragment_view with toolbar and nav bar, and one without, so they won't be shown/hidden when navigation. Without that I don't see a method how to solve problemGlasper
It does not matter if it's nested graph or not you can access any data inside those fragments using ViewModel and set it's liveData in any lifecycle method of the fragment to change a view's properties. I created some examples including nested graphs for child fragments of NavHostFragment of ViewPager inside a fragment of a bottom bar to set navigation for current graph or set visibility of viewpager(this one has some issues). You can check out if you wish hereQuiescent
@Quiescent It matters. Do you understand that I have 1 root_fragment_view (containter) for all my views? And this root contains 3 elements (see xml in the question). I change only the middle part. And if I do toolbar.hide() it hides immediately, and I can see other fragment below that invisible toolbar/bottom nav bar.Glasper
@Quiescent it's really hard to understand before you actually see it. I should have attached video to questionGlasper
@Glasper it's good if the answer from Luis solved your issue. Instead of videos you can also put a gif as image to stackoverflow up to 2mb. I started putting gif when there is an issue with ui requires a motion state, you can convert about 20 seconds of video to gif using web sites. I still don't get how it does matter with ViewModel if you have one NavigationHost or multiple, the thing here is you can set a liveData in a lifecycle of a Fragment and observe changes anywhere you can access to that ViewModel.Quiescent
@Quiescent I added a gif to a question, take a look pleaseGlasper
I think you're overloading the main thread that causes it to glitch on that part of the screen, tries to make an attempt with few data and minor processing @GlasperLuminesce
@Luis Villabolos no, that's not true. Please, keep in mind that when I change destination nav controller changes only middle part of XML in the topic start. And then i hide bottomNavBAr and Toolbar in OnDestinationChangedCallback. That's what causes glitches. Cause this two processes are not synchronized, they can't be synchronized. I see the only way - make that root_layout different for every screen (with or without bottom bar and toolbar)Glasper
L
4

I stuck in this like 2 days but with XML you can solve your problem

  1. You need to wrap your toolbar into CoordinatorLayout
  2. Your toolbar needs scrollFlags: scroll and enter
  3. You need to wrap your fragment in other layour and put in layout_behavior the specific behavior: @string/appbar_scrolling_view_behavior
  4. In your BottomNavigationView put google behavior: com.google.android.material.behavior.HideBottomViewOnScrollBehavior

Something like that:

<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>

By the way, I put the NestedScrollView to make all my fragments ready to scroll and save me other layout where I need it

Luminesce answered 30/6, 2020 at 17:3 Comment(2)
So, how it all works together? I don't see how this is gonna be a solutionGlasper
For me, the solution seems to work, but has a major drawback.. I have a recycler view inside the fragment so it expends the fragment inside the scroll view -> generates a lot of recycler view that are not visible, which is bad for performance ...Immuno

© 2022 - 2024 — McMap. All rights reserved.