61

I have to hide bottom navigation view on up scroll and show on down scroll .how to implement this? my layout is like this

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">


    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:layout_above="@+id/navigation"
        android:layout_alignParentTop="true"
        android:layout_marginBottom="5dp">

        <FrameLayout
            android:id="@+id/container1"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
          />


    </LinearLayout>

    <android.support.design.widget.BottomNavigationView
        android:id="@+id/navigation"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:background="?android:attr/windowBackground"
        app:layout_scrollFlags="scroll|enterAlways|snap"
        app:menu="@menu/dashboard_slider_menu" />

</RelativeLayout>

I have attached screenshot of view. Kindly check it.

enter image description here

Karthik Thunga
  • 1,093
  • 2
  • 12
  • 21

11 Answers11

147

UPDATE Just add one attribute to BottomNavigationView

Material Library AndroidX

<com.google.android.material.bottomnavigation.BottomNavigationView
 ....
 app:layout_behavior="com.google.android.material.behavior.HideBottomViewOnScrollBehavior"/>

Support Library Version 28.0.0 or higher version

<android.support.design.widget.BottomNavigationView
 ....
 app:layout_behavior="@string/hide_bottom_view_on_scroll_behavior"/>

Note:- Your XML should follow the structure of XML given below in old answer.


**OLD ANSWER(Still Works)**

You need a helper class to do this .This solution works like Google Material Design Guideline.

Create a class BottomNavigationViewBehavior

public class BottomNavigationViewBehavior extends CoordinatorLayout.Behavior<BottomNavigationView> {

    private int height;

    @Override
    public boolean onLayoutChild(CoordinatorLayout parent, BottomNavigationView child, int layoutDirection) {
        height = child.getHeight();
        return super.onLayoutChild(parent, child, layoutDirection);
    }

    @Override
    public boolean onStartNestedScroll(@NonNull CoordinatorLayout coordinatorLayout,
                                   BottomNavigationView child, @NonNull 
                                   View directTargetChild, @NonNull View target,
                                   int axes, int type)
    {
        return axes == ViewCompat.SCROLL_AXIS_VERTICAL;
    }

    @Override
    public void onNestedScroll(@NonNull CoordinatorLayout coordinatorLayout, @NonNull BottomNavigationView child,
               @NonNull View target, int dxConsumed, int dyConsumed,
               int dxUnconsumed, int dyUnconsumed, 
                @ViewCompat.NestedScrollType int type)
    {
       if (dyConsumed > 0) {
           slideDown(child);
       } else if (dyConsumed < 0) {
           slideUp(child);
       }
    }

    private void slideUp(BottomNavigationView child) {
        child.clearAnimation();
        child.animate().translationY(0).setDuration(200);
    }

    private void slideDown(BottomNavigationView child) {
        child.clearAnimation();
        child.animate().translationY(height).setDuration(200);
    }
}

For using this behavior you need to use cooradinator layout...

<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.kliff.digitaldwarka.activity.MainActivity">

    <android.support.design.widget.CoordinatorLayout
        android:id="@+id/coordinator_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <android.support.design.widget.AppBarLayout
            android:id="@+id/myAppBar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:descendantFocusability="beforeDescendants"
            android:focusableInTouchMode="true"
            android:theme="@style/AppTheme.AppBarOverlay"
            app:elevation="0dp">

            <android.support.v7.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                android:background="?attr/colorPrimary"
                app:contentInsetStart="0dp"
                app:layout_scrollFlags="scroll|enterAlways"
                app:popupTheme="@style/AppTheme.PopupOverlay"/>
        </android.support.design.widget.AppBarLayout>

        <!---your RecyclerView/Fragment Container Layout-->
        <FrameLayout
             android:id="@+id/container"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
             app:layout_behavior="@string/appbar_scrolling_view_behavior" />
        

         <android.support.design.widget.BottomNavigationView
             android:id="@+id/bottom_nav"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:layout_gravity="bottom"
             app:itemBackground="@color/white"
             app:menu="@menu/bottom_nav_menu" />

      </android.support.design.widget.CoordinatorLayout>

      <!---NavigationView-->
</android.support.v4.widget.DrawerLayout>

Add this code to your Activity that contains bottom nav..

mBottomNavigationView = (BottomNavigationView) findViewById(R.id.bottom_nav);
CoordinatorLayout.LayoutParams layoutParams = (CoordinatorLayout.LayoutParams) mBottomNavigationView.getLayoutParams();
    layoutParams.setBehavior(new BottomNavigationViewBehavior());
Abhishek Singh
  • 9,008
  • 5
  • 28
  • 53
  • @Abhishek Singh If this FrameLayout is a Fragment's container layout, and the RecyclerView is in the ViewPager‘s item.How to make it? – zys Jun 29 '17 at 08:35
  • @Zys.. It will work if you load fragment inside the frame layout.. actually I am doing the same... my frame layout is fragment conatainer...but still if does not work then you can make `NestedScrollView` is parent of your fragments... and `recyclerview.setNestedScrollEnabled(false);` will work for sure – Abhishek Singh Jun 29 '17 at 09:24
  • @AbhishekSingh Thanks !! It works fine. Do you have any hints on how to make the animation match the toolbar animation ? Or how i can apply the same animation to the toolbar ? Cause I noticed that I cannot call setBahviour on AppBarLayout.LayoutParams – Patric Aug 07 '17 at 03:29
  • 4
    @AbhishekSingh how do you deal with the case, when the recycler view doesn't scroll cause everything fits on screen, but the most bottom cell is covered by the bottom navigation view. The bottom navigation would then never hide/disappear leading to the issue that the last row item is covered. – Patric Aug 09 '17 at 04:03
  • @Patric i think that time need calculation that how may item can shown or height of recyclerview<=screen heght and hide by code `mBottomNavigationView.clearAnimation(); mBottomNavigationView.animate().translationY(mBottomNavigationView.getHeight()).setDuration(200);` – Abhishek Singh Aug 09 '17 at 05:50
  • Its not working.. does it necessary to use DrawaerLayout as parent even I'm not using appBar. – RobinHood Oct 27 '17 at 12:48
  • @RobinHood its necessary to use `CoordinatorLayout` not `DrawerLayout` or `AppbarLayout`. Its working perfectly/ – Abhishek Singh Oct 30 '17 at 04:13
  • @AbhishekSingh I tried but no luck, this is my layout look like https://paste.ofcode.org/GCxZ5szY8gZjKh29DfNUJV, let me know what I'm doing wrong. – RobinHood Oct 31 '17 at 10:20
  • @AbhishekSingh thanks, its working fine for recycler view. Is there any way this can be done for listView also? – manish poddar Nov 01 '17 at 07:08
  • 1
    @manishpoddar actually it uses `NestedScrollView`.`RecyclerView` has `NestedScrollView` that why its working with Recycler but not with list. Any content with `NestedScrollView` this works fine but we cannot put list inside nested scroll its bad idea. – Abhishek Singh Nov 01 '17 at 09:59
  • @RobinHood bro you framelayout is fragmentcontainer so fragment should contain recyclerview of Nestedscroll view to work. – Abhishek Singh Nov 01 '17 at 10:03
  • @AbhishekSingh will you post your fragment layout which contain nestedScrollview? – RobinHood Nov 01 '17 at 12:29
  • @AbhishekSingh almost achieved but minor issue, I have 3 tabs, on 1st tab I scroll up and Navigation is hide and at the same time when I change the tab its also hidden over their. – RobinHood Nov 02 '17 at 06:54
  • @RobinHood put this code on fragment resume `getActivity().findViewbyId(R.id.bottom_nav).clearAnimation(); getActivity().findViewbyId(R.id.bottom_nav).animate().translationY(0).setDuration(200);` – Abhishek Singh Nov 02 '17 at 07:25
  • 2
    How do we account for snackbars displaying above the bottom nav? – Atieh Nov 14 '17 at 20:36
  • Even Bottom sheet not only bottom sheet but any views is not visible while using Navigation behavior. – RobinHood Nov 15 '17 at 05:48
  • Consider overriding onNestedPreScroll instead of onNestedScroll (and dy instead of dyConsumed). onNestedScroll sometimes is not called while srolling fast. – s0i1 Dec 28 '17 at 12:05
  • I have the same problem with @zys when the Recycleview is inside a Fragment in ViewPager. But when the Fragment is alone it works fine. – Hosein Hamedi Feb 06 '18 at 17:07
  • @HoseinIT it will work fine inside viewpager. It may be code issue.. replace `framelayout` in above code with `viewpager` layout behaviour element should be define in viewpager too.. and view pager child fragment root node should be nestedscrollview or recycler view – Abhishek Singh Feb 07 '18 at 04:12
  • 12
    Google are such dopes, they specify all these nice Material View animation standards but I can't find official guidance. Zero SDK support for these guidelines so you have to craft it yourself and can only find here on SO.. +1 – angryITguy Jul 20 '18 at 02:57
  • @giulio Check out my latest answer. Latest support lib / AndroidX finally is helping to catch up with the design specs! No more custom code needed since this kind of `Behaviour` class is now provided and can be activated with a single line :) – sunadorer Aug 19 '18 at 11:23
  • 2
    After roughly half a day struggling I got it working by simply adding that line layout_behaviour. The problem was that I was trying different combinations of nested layouts so here's the tip for those who use ConstraintLayout like me: The trick is to use a coordinator layout within a constraint layout. Hope it helps :) – gmartinsnull Nov 15 '18 at 00:00
  • WOW!! Perfect up to date answer. Should be upvoted as much as possible!!! Thanks for this app:layout_behavior="@string/hide_bottom_view_on_scroll_behavior"/ solution!!! Perfect!!! – Sjd Aug 17 '20 at 16:21
  • Does not work while having `CoodinatorLayout` as a parent. – Michał Dobi Dobrzański Aug 08 '22 at 07:32
  • @MichałDobiDobrzański your bottom nav should be direct child of coordinator... And scrolling components also. – Abhishek Singh Aug 08 '22 at 10:42
18

Try this,

 mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                if (dy > 0 && bottom_navigation.isShown()) {
                    bottom_navigation.setVisibility(View.GONE);
                } else if (dy < 0 ) {
                    bottom_navigation.setVisibility(View.VISIBLE);

                }
            }

            @Override
            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {

                super.onScrollStateChanged(recyclerView, newState);
            }
        });

Image while scrolling up :-

click here for scrolling up image

Image while scrolling down:

click here for scrolling down image

Wasim K. Memon
  • 5,979
  • 4
  • 40
  • 55
Rashmi Bhandari
  • 448
  • 4
  • 8
12

Updated answer after the latest library updates:

Hiding the BottomNavigationView on scrolling is now available with just one flag in the layout! Starting from version 28.0.0-alpha1 or the material/androidX 1.0.0-alpha1.

I updated my project using the latter approach since the version now is a stable release candidate. Update: Use fully released version "1.0.0"!

The new out of the box available behaviour is called HideBottomViewOnScrollBehavior. Set it on the BottomNavigationView as app:layout_behavior="@string/hide_bottom_view_on_scroll_behavior" as described in the latest docs.

Here is a full example:

<com.google.android.material.bottomnavigation.BottomNavigationView
        android:id="@+id/navigation"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:labelVisibilityMode="selected"
        app:layout_behavior="@string/hide_bottom_view_on_scroll_behavior"
        android:layout_gravity="bottom"
        app:layout_insetEdge="bottom"
        app:menu="@menu/navigation" />

As with the hiding of the Toolbar on scrolling, you have to ensure that the content is a class that supports the latest scrolling like RecyclerView and NestedScrollView.

This ensures all is working as shown in the animation on the design specs

PS: labelVisibilityMode is another cool addition you get for free for taking the trouble of updating and that is described in depth in the design specs.

sunadorer
  • 3,855
  • 34
  • 42
  • 2
    if in one tab I scroll up bar disappear(as expected) and when press back and jump to another tab screen - tab is still hidden, how to show it? – Choletski Jan 15 '19 at 18:04
  • @Choletski i have the same problem and ask a question SO https://stackoverflow.com/questions/54865536/how-to-show-bottomnavigationbar-again-on-navigate-back – Thomas Meinhart Feb 26 '19 at 06:58
12
  1. Update your project to Androidx i.e Refactor >> Migrate to androidx (Minimum Android studio version 3.4)
  2. Using the default Bottom Navigation Menu xml file, replace the parent Constraint Layout with Coordinator layout.
  3. Add the line app:layout_behavior="com.google.android.material.behavior.HideBottomViewOnScrollBehavior"

i.e

<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".dashboards.Admin_dashboard_main">

    <include layout="@layout/toolbar" />
    <androidx.constraintlayout.widget.ConstraintLayout
        android:id="@+id/main_area"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_constraintTop_toBottomOf="@+id/toolbar"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        android:layout_margin="0dp"
        android:padding="0dp">

        <!-- Fragments Container -->
        <FrameLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layout_behavior="@string/appbar_scrolling_view_behavior"
            tools:context="MainActivity"
            tools:showIn="@layout/activity_tenant_dashboard"
            android:id="@+id/fragment_container">

        </FrameLayout>

    </androidx.constraintlayout.widget.ConstraintLayout>
    <!-- Bottom Navigation View -->

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

</androidx.coordinatorlayout.widget.CoordinatorLayout>
Lefty
  • 1,192
  • 13
  • 18
3

Use this

mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener()
        {
            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy)
            {
                if (dy > 0 ||dy<0 && csButtonLay.isShown())
                {
                    bottomBar.setVisibility(View.GONE);
                }
            }

            @Override
            public void onScrollStateChanged(RecyclerView recyclerView, int newState)
            {
                if (newState == RecyclerView.SCROLL_STATE_IDLE)
                {
                    bottomBar.setVisibility(View.VISIBLE);
                }

                super.onScrollStateChanged(recyclerView, newState);
            }
        });
Anil
  • 1,605
  • 1
  • 14
  • 24
2

Just use CoordinatorLayout as a parent container and add the app:layout_behavior in the child View and set the behavior @string/hide_bottom_view_on_scroll_behavior this is the solution.

<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".Main2Activity">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_above="@id/nav_view"
        android:layout_height="wrap_content"
        app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />
    <com.google.android.material.bottomnavigation.BottomNavigationView
        android:id="@+id/nav_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_gravity="bottom"
        app:layout_behavior="@string/hide_bottom_view_on_scroll_behavior"
        android:background="?android:attr/windowBackground"
        app:menu="@menu/bottom_nav_menu" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>

Happy Coding.

Deepak gupta
  • 827
  • 10
  • 10
1

I encountered this issue working with the Recyclerview. The attribute:

app:layout_behavior="@string/hide_bottom_view_on_scroll_behavior"/>

only partially worked for me, so I had to implement another solution. I defined the BottomNavigationView inside the MainActivity so I had to set a couple of methods to animate it during the scrolling.

class MainActivity : AppCompatActivity() {
private var animator: ObjectAnimator? = null

.
.
.

fun slideDown() {
        nav_view?.let {
            if (animator == null && it.translationY == 0f) {
                animator = translationObjectY(it, 0f, it.height.toFloat() + it.marginBottom.toFloat()).apply {
                    doOnEnd {
                        animator = null
                    }
                }
            }
        }
    }

    fun slideUp() {
        nav_view?.let {
            if (animator == null && it.translationY == it.height.toFloat() + it.marginBottom.toFloat()) {
                animator = translationObjectY(it, it.height.toFloat() + it.marginBottom.toFloat(), 0f).apply {
                    doOnEnd {
                        animator = null
                    }
                }
            }
        }
    }
}

The translationObjectY is an extended function:

fun translationObjectY(
    targetView: View?,
    startY: Float,
    endY: Float,
    duration: Long = 200L
) : ObjectAnimator {
    return ObjectAnimator.ofFloat(targetView, "translationY", startY, endY).apply {
        this.duration = duration
        interpolator = LinearOutSlowInInterpolator()
        start()
    }
}

And I finally create a custom Recyclerview:

class CustomRecyclerView(
    context: Context,
    attrs: AttributeSet?,
    defStyle: Int,
) : RecyclerView(context, attrs, defStyle) {

    constructor(context: Context)
            : this(context, null, 0)

    constructor(context: Context, attrs: AttributeSet)
            : this(context, attrs, 0)

    init {
        this.addOnScrollListener(object : RecyclerView.OnScrollListener() {
            override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
                if (dy > 0) {
                    // Scrolling up
                    hideBottomMenu()
                } else {
                    // Scrolling down
                    showBottomMenu()
                }
            }

            override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
            }
        })
    }

    private fun hideBottomMenu() {
        (context as? MainActivity)?.slideDown()
    }

    private fun showBottomMenu() {
        (context as? MainActivity)?.slideUp()
    }
}

You can then implement it in your fragment like this:

<com.studio.mattiaferigutti.kamasutra.custom.CustomRecyclerView
    android:id="@+id/searchRecycler"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />
Mattia Ferigutti
  • 2,608
  • 1
  • 18
  • 22
0

Just simply add this in your xml

<BottomNavigationView
....
....
app:layout_behavior="@string/hide_bottom_view_on_scroll_behavior"/>
Shaon
  • 2,496
  • 26
  • 27
0

This can help somebody read more:https://material.io/develop/android/components/app-bars-bottom

add app:hideOnScroll="true"

inside BottomAppBar Like below:


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

    ...

    <com.google.android.material.bottomappbar.BottomAppBar
        ...
        app:hideOnScroll="true"
        />

    ...

</androidx.coordinatorlayout.widget.CoordinatorLayout>
Kipkemoi Derek
  • 159
  • 3
  • 5
0

Use this code : when Scrolling down the Recyclerview to your fragment will hide the bottom navigation. then when Scrolled Up it will show the Bottom nav.

private View view;
private AppCompatActivity activity;
private ChipNavigationBar chipNavigationBar;
//...............................................

@Override
    public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        if (view == null) {
            view = inflater.inflate(R.layout.list_fragment, container, false);
         hide_NavigationBar_adwhen_Scrolling();
        }
        return view;
    }

//...........................................................

private void hide_NavigationBar_adwhen_Scrolling() {
        activity = (AppCompatActivity) view.getContext();
        chipNavigationBar = activity.findViewById(R.id.chipNavigation);

        RecyclerView recyclerView = view.findViewById(R.id.recylerView);
       recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
        @Override
        public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
            if (dy > 0) {//on_Scrolled_down
                //  chipNavigationBar.animate().translationY(200).setDuration(500);
               chipNavigationBar.animate().translationY(banner_ad_card_1.getHeight()).setDuration(1000);

            } else {//on_Scrolled_up
                 chipNavigationBar.setVisibility(View.VISIBLE);
                chipNavigationBar.animate().translationY(0).setDuration(1000);
                //  chipNavigationBar.setItemSelected(R.id.home, true);
            }
        }

        @Override
        public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
            super.onScrollStateChanged(recyclerView, newState);
        }
    });
    }
NI Shihab
  • 1
  • 1
0
 mScrollView.setOnScrollChangeListener(new NestedScrollView.OnScrollChangeListener() {
            @Override
            public void onScrollChange(NestedScrollView v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {


                if((scrollY > oldScrollY)) {

                        navigationView.setVisibility(View.GONE);

                }else {

                        navigationView.setVisibility(View.VISIBLE);

                }
            }

        });
vibhu norby
  • 156
  • 4