user4546546
user4546546

Reputation:

Hide FAB in NestedScrollView when scrolling

I am having a nestedscrollview with content like some linearlayouts and textviews. I am using a floatingactionbutton library for some reasons, as well. So I can't use any behavior for it. I don't know how I should handle the scrollchangelistener from scrollview to hide and show the fab dynamically like a behavior.

Any suggestions how to hide and show the fab while scrolling?

Upvotes: 16

Views: 16484

Answers (5)

Jay Panchal
Jay Panchal

Reputation: 413

You can use this listener to observe and hide FAB when scrolling.

   nestedScrollView.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {
                @Override
                public void onScrollChanged() {
                    if (nestedScrollView != null) {
                        if (nestedScrollView.getChildAt(0).getBottom() <= (nestedScrollView.getHeight() + nestedScrollView.getScrollY())) {
                            fab.setVisibility(View.INVISIBLE);
                        } else {
                            fab.setVisibility(View.VISIBLE);
                        }
                    }
                }
            });

Upvotes: 0

Jay Thummar
Jay Thummar

Reputation: 2299

After spending such time i have found the solution for it. It may work in all situations. Though it is a hack not the proper solution but you can apply it to make this thing work.

As we know setOnScrollChangeListener will only work if minimum api 23, so what if my minimum api level is less then 23.

So I found out solution from stack overflow that we can use getViewTreeObserver().addOnScrollChangedListener for that so this will be compatible solution for all devices.

Now let's move to the final solution of over problem "Hide fab button when nested scroll view scrolling and Show fab button when nested scroll view in ideal state"

So for that we can use Handler with postDelayed to slove this issue.

  1. Define on variable in you context private int previousScrollY = 0;

  2. Then use getViewTreeObserver().addOnScrollChangedListener to your nested scroll view like this.

NESTEDSCROLLVIEW.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() { @Override public void onScrollChanged() { new Handler().postDelayed(new Runnable() { @Override public void run() { if (NESTEDSCROLLVIEW.getScrollY() == previousScrollY) { FABBUTTON.setVisibility(View.VISIBLE); } else { FABBUTTON.setVisibility(View.INVISIBLE); } } }, 10); previousScrollY = NESTEDSCROLLVIEW.getScrollY(); } });

  1. Now you are ready to go....

Upvotes: 2

Henrique Monte
Henrique Monte

Reputation: 1284

Simple add this code below to your NestedScrollView ScrollChangeListener:

NestedScrollView nsv = v.findViewById(R.id.nsv);
    nsv.setOnScrollChangeListener(new NestedScrollView.OnScrollChangeListener() {
        @Override
        public void onScrollChange(NestedScrollView v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
            if (scrollY > oldScrollY) {
                fab.hide();
            } else {
                fab.show();
            }
        }
    });

Upvotes: 39

yousef
yousef

Reputation: 1363

define variable type int in your Activity or fragment to set previous Scroll from ScrollView then use this method to listen change scroll in ScrollView Class

 scrollView.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {
        @Override
        public void onScrollChanged() {

    // previousScrollY this variable is define in your Activity or Fragment
            if (scrollView.getScrollY() > previousScrollY && floatingActionButton.getVisibility() == View.VISIBLE) {
                floatingActionButton.hide();
            } else if (scrollView.getScrollY() < previousScrollY && floatingActionButton.getVisibility() != View.VISIBLE) {
                floatingActionButton.show();
            }
            previousScrollY = scrollView.getScrollY();
        }
    });

will work done all version of android

Upvotes: 3

Tigran Sarkisian
Tigran Sarkisian

Reputation: 1093

Create FabScrollBehavior class

public class FabScrollBehavior extends CoordinatorLayout.Behavior<FloatingActionButton> {
    private int toolbarHeight;

    public FabScrollBehavior(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.toolbarHeight = AppUtil.getToolbarHeight(context);
    }

    @Override
    public boolean layoutDependsOn(CoordinatorLayout parent, FloatingActionButton fab, View dependency) {
        return dependency instanceof AppBarLayout;
    }

    @Override
    public boolean onDependentViewChanged(CoordinatorLayout parent, FloatingActionButton fab, View dependency) {
        if (dependency instanceof AppBarLayout) {
            CoordinatorLayout.LayoutParams lp = (CoordinatorLayout.LayoutParams) fab.getLayoutParams();
            int fabBottomMargin = lp.bottomMargin;
            int distanceToScroll = fab.getHeight() + fabBottomMargin;
            float ratio = (float)dependency.getY()/(float)toolbarHeight;
            fab.setTranslationY(-distanceToScroll * ratio);
        }
        return true;
    }
}

Where AppUtil.getToolbarHeight(context) is -

public static int getToolbarHeight(Context context) {
        final TypedArray styledAttributes = context.getTheme().obtainStyledAttributes(
                new int[]{R.attr.actionBarSize});
        int toolbarHeight = (int) styledAttributes.getDimension(0, 0);
        styledAttributes.recycle();

        return toolbarHeight;
    }

then in your layout add to FloatingActionButton layout_behavior:

   <android.support.design.widget.FloatingActionButton
        android:id="@+id/fab_task_accept"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="end|bottom"
        android:layout_margin="@dimen/fab_margin"
        android:src="@drawable/ic_accepted"
        app:layout_behavior="pass.to.your.FabScrollBehavior.Class"
        app:theme="@style/Widget.AppTheme.Fab"/>

The whole layout looks like

<?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"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:animateLayoutChanges="true"
    android:orientation="vertical">

    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/Widget.AppTheme.AppBarOverlay">

        <include
            layout="@layout/include_layout_toolbar_scroll"/>

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


    <include layout="@layout/include_layout_content_with_nestedscroll"/>

    <android.support.design.widget.FloatingActionButton
        android:id="@+id/fab_task_accept"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="end|bottom"
        android:layout_margin="@dimen/fab_margin"
        android:src="@drawable/ic_accepted"
        app:layout_behavior="pass.to.FabScrollBehavior.Class"
        app:theme="@style/Widget.AppTheme.Fab"/>


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

Implemented from https://mzgreen.github.io/2015/02/15/How-to-hideshow-Toolbar-when-list-is-scroling(part1)/

Upvotes: 12

Related Questions