Anchor FloatingActionButton (Button) To RecyclerView and Hide/Show On Scroll (Kotlin)

If you are using Android Studio -> File -> New -> Activity -> Scrolling Activity with FloatingActionButton anchored to AppBarLayout with CollapsingToolbarLayout, FloatingActionButton is capable of automatic show and hide on scroll.

Sadly, by anchoring FloatingActionButton to NestedScrollView or RecyclerView (or shown without anchor), automatic show and hide FloatingActionButton on scroll doesn't work.

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.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/rootView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="false"
    tools:context="com.mydomain.myapp.MainActivity">

    <android.support.design.widget.AppBarLayout
        android:id="@+id/appBar"
        android:layout_width="match_parent"
        android:layout_height="@dimen/app_bar_height"
        android:fitsSystemWindows="true"
        android:theme="@style/AppTheme.AppBarOverlay"
        app:expanded="true">

        <!-- app:layout_scrollFlags="scroll|exitUntilCollapsed" -->
        <android.support.design.widget.CollapsingToolbarLayout
            android:id="@+id/toolbarLayout"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:fitsSystemWindows="true"
            app:contentScrim="?attr/colorPrimary"
            app:layout_scrollFlags="scroll|exitUntilCollapsed"
            app:toolbarId="@+id/toolbar">

            <android.support.v7.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                app:layout_collapseMode="pin"
                app:popupTheme="@style/AppTheme.PopupOverlay" />

        </android.support.design.widget.CollapsingToolbarLayout>
    </android.support.design.widget.AppBarLayout>

    <android.support.v4.widget.NestedScrollView
        android:id="@+id/scrollView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior"
        >

    </android.support.v4.widget.NestedScrollView>

    <android.support.design.widget.FloatingActionButton
        android:id="@+id/fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="@dimen/fab_margin"
        app:layout_anchor="@id/appBar"
        app:layout_anchorGravity="bottom|end"
        android:tint="@color/fab_tint"
        app:srcCompat="@drawable/ic_edit_black_24dp" />

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

To enable FloatingActionButton to automatic show and hide on scroll, we need to create ScrollAwareFABBehavior by extending FloatingActionButton.Behavior.The following code is based on CodePath's code and code suggestion by jairobjunior.

class ScrollAwareFABBehavior(context: Context, attrs: AttributeSet): FloatingActionButton.Behavior(context, attrs) {    override fun onStartNestedScroll(coordinatorLayout: CoordinatorLayout,                                     child: FloatingActionButton, directTargetChild: View, target: View,                                     axes: Int, type: Int): Boolean {        return axes == ViewCompat.SCROLL_AXIS_VERTICAL || super.onStartNestedScroll(coordinatorLayout,                child, directTargetChild, target, axes, type)    }    override fun onNestedScroll(coordinatorLayout: CoordinatorLayout,                                child: FloatingActionButton, target: View, dxConsumed: Int, dyConsumed: Int,                                dxUnconsumed: Int, dyUnconsumed: Int, type: Int) {        super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed,                dyUnconsumed, type)        if (dyConsumed > 0 && child.visibility == View.VISIBLE) {            child.hide(object : FloatingActionButton.OnVisibilityChangedListener() {                override fun onHidden(fab: FloatingActionButton) {                    super.onHidden(fab)                    fab.visibility = View.INVISIBLE                }            })        // } else if (dyUnconsumed < 0 && child.visibility != View.VISIBLE) {        } else if (dyConsumed < 0 && child.visibility != View.VISIBLE) {            child.show()        }    }}

Set FloatingActionButton app:layout_behavior to ScrollAwareFABBehavior for fab to auto hide and show on scroll.

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

    <android.support.design.widget.FloatingActionButton
        android:id="@+id/fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|end"
        app:layout_behavior="com.mydomain.myapp.ScrollAwareFABBehavior"
        android:layout_margin="@dimen/fab_margin"
        android:tint="@color/fab_tint"
        app:srcCompat="@drawable/ic_add_black_24dp" />

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

❤️ Is this article helpful?

Buy me a coffee ☕ or support my work via PayPal to keep this space 🖖 and ad-free.

Do send some 💖 to @d_luaz or share this article.

✨ By Desmond Lua

A dream boy who enjoys making apps, travelling and making youtube videos. Follow me on @d_luaz

👶 Apps I built

Travelopy - discover travel places in Malaysia, Singapore, Taiwan, Japan.