14

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.

stan0
  • 11,549
  • 6
  • 42
  • 59

2 Answers2

23

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.

stan0
  • 11,549
  • 6
  • 42
  • 59
  • 1
    Thank you! Btw **onStartNestedScroll** and **onNestedPreScroll** are now deprecated. Both need `int type` as the last parameter ;-) – Jokus Apr 05 '18 at 08:22
  • 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. – stan0 Apr 05 '18 at 08:46
  • 1
    https://android.jlelse.eu/scroll-your-bottom-navigation-view-away-with-10-lines-of-code-346f1ed40e9e – Debjit Jul 19 '18 at 15:52
  • What do i do if I want the opposite. A header layout going off the screen. – Debjit Jul 19 '18 at 15:56
  • @Debjit if you mean the App Bar Layout then you could use its default behaviour -> https://developer.android.com/reference/android/support/design/widget/AppBarLayout.Behavior – stan0 Jul 20 '18 at 06:34
  • @stan0 No not app bar. I have a layout on top which needs to quick return. – Debjit Jul 21 '18 at 12:16
  • 1
    Support library has an integrated hide_bottom_view_on_scroll_behavior doing the same. – Softlion Jan 22 '19 at 14:54
  • This is not Material. you are using support library. – kelalaka Jan 12 '20 at 10:50
5

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.

Cameron Ketcham
  • 7,966
  • 2
  • 28
  • 27
  • 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 Jul 20 '18 at 06:32
  • Have you tested it till now? If yes, can you please tell me how to use this? – manish poddar Aug 09 '18 at 10:22
  • Take a look at the source, it's pretty simple. https://github.com/material-components/material-components-android/blob/master/lib/java/com/google/android/material/behavior/HideBottomViewOnScrollBehavior.java – Cameron Ketcham Aug 10 '18 at 18:26