Show/hide BottomNavigationView on scroll in CoordinatorLayout with AppBarLayout

13,657

Solution 1

After a day or two of searching I settled with a custom Behavior attached to the BottomNavigationView. Its main idea is to detect when the BottomNavigationView's sibling is scrolled so that it can hide the BottomNavigationView. Something like this:

public class BottomNavigationBehavior extends CoordinatorLayout.Behavior<BottomNavigationView> {

    public BottomNavigationBehavior() {
        super();
    }

    public BottomNavigationBehavior(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public boolean layoutDependsOn(CoordinatorLayout parent, BottomNavigationView child, View dependency) {
        boolean dependsOn = dependency instanceof FrameLayout;
        return dependsOn;
    }

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

    @Override
    public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, BottomNavigationView child, View target, int dx, int dy, int[] consumed) {
        if(dy < 0) {
            showBottomNavigationView(child);
        }
        else if(dy > 0) {
            hideBottomNavigationView(child);
        }
    }

    private void hideBottomNavigationView(BottomNavigationView view) {
        view.animate().translationY(view.getHeight());
    }

    private void showBottomNavigationView(BottomNavigationView view) {
        view.animate().translationY(0);
    }
}

As you can see, I'm using simple ViewPropertyAnimator, obtained using the child views's animate method. This leads to a simple animation that doesn't really match the AppBarLayout's behavior but it's decent enough to look good and at the same time it's simple enough to implement.

I expect that at some point the Android team will add a default Behavior for the BottomNavigationView in the support library so I don't think it's reasonable to invest a lot more time to exactly duplicate the AppBarLayout's behavior.

edit (April 2018): see the comments section for a minor clarification about onStartNestedScroll and onNestedPreScroll and their new versions.

Solution 2

You can also use HideBottomViewOnScrollBehavior. This behavior works in basically the same way, but also handles cancelling any existing animations that are running which should be better for performance.

Share:
13,657
stan0
Author by

stan0

Software development, machine learning and data science.

Updated on June 11, 2022

Comments

  • stan0
    stan0 almost 2 years

    I am trying to use both AppBarLayout and BottomNavigationLayout in a single CoordinatorLayout and I'm having difficulties hiding the BottomNavigationLayout as required by the material guideline.

    I mean something like this:

    <android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fitsSystemWindows="false">
    
        <android.support.design.widget.AppBarLayout
            android:id="@+id/app_bar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:layout_insetEdge="top"
            android:theme="@style/AppTheme.AppBarOverlay">
    
            <android.support.v7.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                app:popupTheme="@style/AppTheme.PopupOverlay"
                app:layout_scrollFlags="scroll|enterAlways"/>
        </android.support.design.widget.AppBarLayout>
    
    
        <android.support.design.widget.BottomNavigationView
            android:id="@+id/bottom_nav"
            android:layout_width="match_parent"
            android:layout_height="56dp"
            android:layout_gravity="bottom"
            app:menu="@menu/menu_bottom_navigation"/>
    
        <FrameLayout
            android:id="@+id/content_container"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="top"
            app:layout_behavior="@string/appbar_scrolling_view_behavior"/>
    
    </android.support.design.widget.CoordinatorLayout>
    

    As you can see, I also have a FrameLayout that's used to contain a fragment with the actual content. Currently there are no default/built-in behaviors for the BottomNavigationView - neither for the view itself, nor for its siblings. The existing appbar_scrolling_view_behavior handles the content view in coordination with the appbar but ignores other siblings.

    I am looking for a solution to hide and show both the appbar and the bottom navigation view on scroll.

  • Jokus
    Jokus about 6 years
    Thank you! Btw onStartNestedScroll and onNestedPreScroll are now deprecated. Both need int type as the last parameter ;-)
  • stan0
    stan0 about 6 years
    Thanks @Jokus I haven't used the BottomNavBar since this post but i'll try to take a look and edit as needed. Thanks for the clarification - it could be useful for others.
  • Debjit
    Debjit almost 6 years
  • Debjit
    Debjit almost 6 years
    What do i do if I want the opposite. A header layout going off the screen.
  • stan0
    stan0 almost 6 years
    This looks promising! It's probably the correct way to do it nowadays but unfortunately I don't have the time to test it now. So I hope other users would be able to test and upvote in order to improve this question/answer.
  • stan0
    stan0 almost 6 years
    @Debjit if you mean the App Bar Layout then you could use its default behaviour -> developer.android.com/reference/android/support/design/widge‌​t/…
  • Debjit
    Debjit almost 6 years
    @stan0 No not app bar. I have a layout on top which needs to quick return.
  • manish poddar
    manish poddar almost 6 years
    Have you tested it till now? If yes, can you please tell me how to use this?
  • Cameron Ketcham
    Cameron Ketcham almost 6 years
    Take a look at the source, it's pretty simple. github.com/material-components/material-components-android/b‌​lob/…
  • Softlion
    Softlion over 5 years
    Support library has an integrated hide_bottom_view_on_scroll_behavior doing the same.
  • kelalaka
    kelalaka over 4 years
    This is not Material. you are using support library.