Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

F.A.B Hides but Doesn't Show

Trying to implement a Floating Action Button (F.A.B) that hides on scroll down, and shows on scroll up.

I have ScrollAwareFABBehavior.java to manage this, and it's connected to the F.A.B in in the XML activity_main. Problem: The F.A.B hides on scroll down, but doesn't show again when I scroll up. I logged the onNestedScroll method and it calls "calling scroll" and "calling to hide" while scrolling down; but after the F.A.B is hidden there are none of the 3x Log's

Question: Why does the F.A.B not show when I scroll up, after the F.A.B has been hidden.

ScrollAwareFABBehavior.java:

import android.content.Context;
import android.support.design.widget.CoordinatorLayout;
import android.support.design.widget.FloatingActionButton;
import android.support.v4.view.ViewCompat;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;

public class ScrollAwareFABBehavior extends FloatingActionButton.Behavior {
    public ScrollAwareFABBehavior(Context context, AttributeSet attrs) {
        super();
    }

    @Override
    public boolean onStartNestedScroll(final CoordinatorLayout coordinatorLayout, final FloatingActionButton child,
                                       final View directTargetChild, final View target, final int nestedScrollAxes) {
        // Ensure we react to vertical scrolling
        return nestedScrollAxes == ViewCompat.SCROLL_AXIS_VERTICAL
                || super.onStartNestedScroll(coordinatorLayout, child, directTargetChild, target, nestedScrollAxes);
    }

    @Override
    public void onNestedScroll(final CoordinatorLayout coordinatorLayout, final FloatingActionButton child,
                               final View target, final int dxConsumed, final int dyConsumed,
                               final int dxUnconsumed, final int dyUnconsumed) {
        super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed);
        Log.d("test", "calling scroll");
        if (dyConsumed > 0 && child.getVisibility() == View.VISIBLE) {
            // User scrolled down and the FAB is currently visible -> hide the FAB
            Log.d("test", "calling to hide");
            child.hide();
        } else if (dyConsumed < 0 && child.getVisibility() != View.VISIBLE) {
            // User scrolled up and the FAB is currently not visible -> show the FAB
            Log.d("test", "calling to show");
            child.show();
        }
    }
}

activity_main.xml:

<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/main_content"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="companyname.appname.MainActivity">


        <android.support.v7.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
            android:id="@+id/rv_contactlist"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:clipToPadding="false"
            android:paddingBottom="16dp"
            android:paddingTop="16dp"
            android:scrollbars="vertical" />

        <android.support.design.widget.FloatingActionButton

            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="bottom|end"
            android:layout_margin="16dp"
            android:src="@drawable/ic_add_circle_outline_black_24dp"
            app:layout_anchor="@id/rv_contactlist"
            app:layout_anchorGravity="bottom|right|end"
            android:layout_alignParentEnd="true"
            app:fabSize="normal"
            android:layout_alignParentBottom="true"
            android:onClick="addItem"
            app:layout_behavior="companyname.appname.ScrollAwareFABBehavior"/>

</android.support.design.widget.CoordinatorLayout>
like image 532
Tom James Avatar asked Nov 30 '22 22:11

Tom James


2 Answers

Which support library version are you using in your project?

If you are using the latest one ( I mean 25.0.x), this is because fab.hide() method set the visibility to be View.GONE. This makes nested scroll listener stop to check fab, the second time you try to scroll the list.

More detail can be found here: https://code.google.com/p/android/issues/detail?id=230298

And I search a bit found this similar question already have a nice answer: Floating action button not visible on scrolling after updating Google Support & Design Library

So a possible work around would be to override fab.hide method, not to set the visibility to GONE but INVISIBLE instead.

And I think this may be fixed from upstream later, so just keep an eye on it.

like image 93
Anthonyeef Avatar answered Dec 02 '22 11:12

Anthonyeef


Because the update of Android to 25.0.x+ you should set the fab button with the listener to INVISBLE to show again the fab button, my solution is the next:

public class ScrollAwareFABBehavior extends FloatingActionButton.Behavior {
private static final String TAG = "ScrollAwareFABBehavior";

public ScrollAwareFABBehavior(Context context, AttributeSet attrs) {
    super();
}


@Override
public boolean onStartNestedScroll(@NonNull CoordinatorLayout coordinatorLayout, @NonNull FloatingActionButton child, @NonNull View directTargetChild, @NonNull View target, int axes, int type) {
    return true;
}

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

    return false;
}

@Override
public void onNestedScroll(@NonNull CoordinatorLayout coordinatorLayout, @NonNull FloatingActionButton child, @NonNull View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, int type) {
    super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, type);

    if (dyConsumed > 0 && child.getVisibility() == View.VISIBLE) {
        child.hide(new FloatingActionButton.OnVisibilityChangedListener() {
                       @Override
                       public void onHidden(FloatingActionButton fab) {
                           super.onHidden(fab);
                           fab.setVisibility(View.INVISIBLE);
                       }
                   }
        );
    } else if (dyConsumed < 0 && child.getVisibility() != View.VISIBLE) {
        child.show();
    }
}
}

** Tested in a Nexus 6P with Android Oreo.

like image 30
Ivor Avatar answered Dec 02 '22 13:12

Ivor