Hide/Show bottomNavigationView on Scroll
Asked Answered
C

11

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

Citrange answered 27/6, 2017 at 10:23 Comment(5)
What did you try ?Dementia
Add event/gesture listener on your list view / recycler view. Hide/show based on the event.Lazybones
R u using RecyclerViewAvicenna
ya.. am using recyclerviewCitrange
@KarthikThunga check my answer belowSurefire
S
149

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());
Surefire answered 27/6, 2017 at 10:51 Comment(25)
@Abhishek Singh If this FrameLayout is a Fragment's container layout, and the RecyclerView is in the ViewPager‘s item.How to make it?Auriga
@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 sureSurefire
@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.LayoutParamsMusicianship
@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.Musicianship
@Musicianship 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);Surefire
Its not working.. does it necessary to use DrawaerLayout as parent even I'm not using appBar.Ursas
@Ursas its necessary to use CoordinatorLayout not DrawerLayout or AppbarLayout. Its working perfectly/Surefire
@AbhishekSingh I tried but no luck, this is my layout look like paste.ofcode.org/GCxZ5szY8gZjKh29DfNUJV, let me know what I'm doing wrong.Ursas
@AbhishekSingh thanks, its working fine for recycler view. Is there any way this can be done for listView also?Cantor
@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.Surefire
@Ursas bro you framelayout is fragmentcontainer so fragment should contain recyclerview of Nestedscroll view to work.Surefire
@AbhishekSingh will you post your fragment layout which contain nestedScrollview?Ursas
@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.Ursas
@Ursas put this code on fragment resume getActivity().findViewbyId(R.id.bottom_nav).clearAnimation(); getActivity().findViewbyId(R.id.bottom_nav).animate().translationY(0).setDuration(200);Surefire
How do we account for snackbars displaying above the bottom nav?Rusch
Even Bottom sheet not only bottom sheet but any views is not visible while using Navigation behavior.Ursas
Consider overriding onNestedPreScroll instead of onNestedScroll (and dy instead of dyConsumed). onNestedScroll sometimes is not called while srolling fast.Shillong
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.Khichabia
@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 viewSurefire
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.. +1Othilie
@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 :)Medorra
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 :)Lonna
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!!!Doglike
Does not work while having CoodinatorLayout as a parent.Hedgehog
@MichałDobiDobrzański your bottom nav should be direct child of coordinator... And scrolling components also.Surefire
H
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

Hinkley answered 27/6, 2017 at 11:29 Comment(4)
How to hide bottom navigation when no element found. I am using Visibility GONE, but the problem is when scrolling on recycler view bottom navigation shadow display now.Wheedle
Can you add the screen shot because normally it won'tHinkley
Please look below this picture.Wheedle
What if the recyclerview is in the fragment? And the bottom navigation is in the activity and there is only a framelayout above it served as a placeholder for the fragments.Millrace
M
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.

Medorra answered 19/8, 2018 at 11:20 Comment(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?Wonky
@Wonky i have the same problem and ask a question SO #54866036Caboose
H
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>
Haddad answered 10/6, 2019 at 10:12 Comment(0)
A
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);
            }
        });
Avicenna answered 27/6, 2017 at 10:29 Comment(0)
C
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.

Cuttlefish answered 12/9, 2019 at 12:12 Comment(0)
C
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" />
Cuxhaven answered 11/12, 2020 at 12:3 Comment(0)
B
0

Just simply add this in your xml

<BottomNavigationView
....
....
app:layout_behavior="@string/hide_bottom_view_on_scroll_behavior"/>
Bithynia answered 5/5, 2020 at 9:57 Comment(0)
S
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>
Stove answered 28/8, 2020 at 10:55 Comment(0)
M
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);
        }
    });
    }
Miramirabeau answered 12/6, 2022 at 10:33 Comment(0)
U
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);

                }
            }

        });
Unconstitutional answered 13/4, 2023 at 10:26 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.