Hide FAB in NestedScrollView when scrolling
Asked Answered
D

5

16

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?

Devin answered 1/1, 2016 at 22:42 Comment(5)
Check these solutions: #32038832Byte
Have already. Nothing works.Devin
Read carefully: plus.google.com/+IanLake/posts/haQL1mnTzaw and check cheesesquare on GitHubByte
@Byte please note, that im using a different library for my floatingactionbutton that doesnt support behavior's, so if i try and add the "app:layout_behavior="package", the app crashes. cheesesquare is using the default floatingactionbutton.Devin
sorry I'd forgotten about it. So ask author of this library, I mean create issue on Github pageByte
L
39

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();
            }
        }
    });
Lylalyle answered 27/2, 2017 at 16:23 Comment(6)
This requires API level 23 or above.Petes
Are you sure? I use it in API level 19.Lylalyle
I am very sure. Have a look here. You will find a text saying "Added in API level 23" in the top right corner and your IDE should be pointing that out as well.Petes
Yeah, you're right, but I think that NestedScrollView.setOnScrollChangeListener works with API v4 Please, have a look here: developer.android.com/reference/android/support/v4/widget/…Lylalyle
You need to import this: android.support.v4.widget.NestedScrollView;Lylalyle
That is true. It does work that way, but then it only works on NestedScrollView's.Petes
R
12

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)/

Rickierickman answered 16/2, 2016 at 8:38 Comment(1)
Awesome, but the layout_behavior just use "pass.to.FabScrollBehavior"Fraunhofer
S
3

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

Slopwork answered 26/3, 2018 at 13:14 Comment(1)
This is not reliable. It works sporadically. Also, when scrolling ends, FAB should show for better ux, which is not possible as state could not read.Negatron
T
2

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....
Trangtranquada answered 20/11, 2019 at 5:10 Comment(0)
A
0

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);
                        }
                    }
                }
            });
Aberration answered 7/7, 2021 at 6:39 Comment(1)
Code-only answers are low-quality answers.Marlite

© 2022 - 2024 — McMap. All rights reserved.