Search code examples
scrollandroid-recyclerviewfloating-action-buttonandroid-coordinatorlayout

Hide FloatingActionButton on scroll of RecyclerView


I want to hide/show FloatingActionButton on scroll of RecyclerView.

My XML layout :

<android.support.design.widget.CoordinatorLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent" >

            <android.support.v7.widget.RecyclerView
                android:id="@+id/recyclerview_eventlist"
                android:layout_width="match_parent"
                android:layout_height="match_parent" />

            <android.support.design.widget.FloatingActionButton
                android:id="@+id/fab_createevent"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_margin="@dimen/fab_margin"
                app:layout_anchor="@id/recyclerview_eventlist"
                app:layout_anchorGravity="bottom|right|end"
                app:layout_behavior="com.eventizon.behavior.ScrollAwareFABBehavior"
                android:src="@drawable/ic_edit"
                app:backgroundTint="@color/custom_color_1"
                app:borderWidth="0dp" />
        </android.support.design.widget.CoordinatorLayout>

DrawerLayout is the parent layout of this layout.

    public class ScrollAwareFABBehavior extends FloatingActionButton.Behavior {


    private static final String TAG = "ScrollAwareFABBehavior";

    public ScrollAwareFABBehavior(Context context, AttributeSet attrs) {
        super();
        Log.e(TAG,"ScrollAwareFABBehavior");
    }

    @Override
    public void onNestedScroll(CoordinatorLayout coordinatorLayout,
            FloatingActionButton child, View target, int dxConsumed,
            int dyConsumed, int dxUnconsumed, int dyUnconsumed) {
        // TODO Auto-generated method stub
        super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed,
                dxUnconsumed, dyUnconsumed);
        Log.e(TAG,"onNestedScroll called");
        if (dyConsumed > 0 && child.getVisibility() == View.VISIBLE) {
            Log.e(TAG,"child.hide()");
            child.hide();
        } else if (dyConsumed < 0 && child.getVisibility() != View.VISIBLE) {
            Log.e(TAG,"child.show()");
            child.show();
        }
    }
}

Used this layout behaviour for FloatingActionButton.

When I see logcat only constructor is getting called. onNestedScroll() doesn't get called when I scroll the list.


Solution

  • Ok, here is what you need:

    First, since your FAB depends on the RecyclerView, add the following to your behavior class:

    @Override
    public boolean layoutDependsOn(CoordinatorLayout parent, FloatingActionButton child, View dependency) {
        if(dependency instanceof RecyclerView)
            return true;
    
        return false;
    }
    

    Next, in order to receive onNestedScroll() calls, you need to override this:

     public boolean onStartNestedScroll(CoordinatorLayout parent, FloatingActionButton child, View directTargetChild, View target, int nestedScrollAxes) {
    
        //predict whether you will need to react to the RecyclerView's scroll;
        //if yes, return true, otherwise return false to avoid future calls
        //of onNestedScroll()
        return true;
    }
    

    Good luck!

    Update

    Here is what your ScrollAwareFABBehavior should look like:

    public class ScrollAwareFABBehavior extends FloatingActionButton.Behavior {
        private static final String TAG = "ScrollAwareFABBehavior";
    
        public ScrollAwareFABBehavior(Context context, AttributeSet attrs) {
            super();
        }
    
        public boolean onStartNestedScroll(CoordinatorLayout parent, FloatingActionButton child, View directTargetChild, View target, int nestedScrollAxes) {
            return true;
        }
    
        @Override
        public boolean layoutDependsOn(CoordinatorLayout parent, FloatingActionButton child, View dependency) {
            if(dependency instanceof RecyclerView)
                return true;
    
            return false;
        }
    
        @Override
        public void onNestedScroll(CoordinatorLayout coordinatorLayout,
                                   FloatingActionButton child, View target, int dxConsumed,
                                   int dyConsumed, int dxUnconsumed, int dyUnconsumed) {
            // TODO Auto-generated method stub
            super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed,
                    dxUnconsumed, dyUnconsumed);
    
            if (dyConsumed > 0 && child.getVisibility() == View.VISIBLE) {    
                child.hide();
            } else if (dyConsumed < 0 && child.getVisibility() != View.VISIBLE) {
                child.show();
            }
        }
    }
    

    Also, it was tested using com.android.support:design:23.0.1