Clans / FloatingActionButton

Android Floating Action Button based on Material Design specification
Apache License 2.0
5.23k stars 1.13k forks source link

FloatingActionButton/Menu hide on ListView scroll #299

Open tieuphu9x opened 8 years ago

tieuphu9x commented 8 years ago

I want to hide/show FloatingActionButton/Menu on scroll of ListView. How to do this?

ifarshgar commented 8 years ago

i found the solution for this.

use this attribute: app:layout_behavior="com.example.FABBehavior"

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

import com.github.clans.fab.FloatingActionMenu;

import java.util.List;

public class FABBehavior extends CoordinatorLayout.Behavior<FloatingActionMenu> {
    private int toolbarHeight;

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

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

    @Override
    public boolean onDependentViewChanged(CoordinatorLayout parent, FloatingActionMenu 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;
    }
}
shihabmi7 commented 8 years ago

@Rahman-94 I am also stuck with the same issue. How to set Utils.getToolbarHeight(context) ; need this method badly.. and not works after set the had code value to this.

eric-taix commented 7 years ago

I had the same issue as @shihabmi7 and was able to solve it. My FloatingActionMenu is inside a FrameLayout so I decided to add the behavior to the FrameLayout.

<FrameLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"     
    app:layout_behavior="my.package.FloatingActionMenuInFrameLayoutBehavior">

            <com.github.clans.fab.FloatingActionMenu
                android:layout_width="wrap_content"
                .....
           </com.github.clans.fab.FloatingActionMenu>
    </FrameLayout>

And the behavior code :


public class FloatingActionMenuInFrameLayoutBehavior extends CoordinatorLayout.Behavior<FrameLayout> {

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

    @Override
    public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, FrameLayout child, View directTargetChild, View target, int nestedScrollAxes) {
        return nestedScrollAxes == ViewCompat.SCROLL_AXIS_VERTICAL || super.onStartNestedScroll(coordinatorLayout, child, directTargetChild, target, nestedScrollAxes);
    }

    @Override
    public void onNestedScroll(CoordinatorLayout coordinatorLayout, FrameLayout fabContainer, View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {
        super.onNestedScroll(coordinatorLayout, fabContainer, target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed);
        FloatingActionMenu fabMenu = (FloatingActionMenu) fabContainer.getChildAt(0);
        if (dyConsumed > 0 && !fabMenu.isMenuButtonHidden()) {
            fabMenu.hideMenuButton(true);
        } else if (dyConsumed < 0 && fabMenu.isMenuButtonHidden()) {
            fabMenu.showMenuButton(true);
        }
    }
}

Adapt this to your desired behavior ;-) Hope it helps

fmrsabino commented 7 years ago

I think this one might be an improvement on the solution provided by @eric-taix (you can apply it directly to your FloatingActionMenu and has a threshold (equal to half of the height of the FAB).

class FloatingActionButtonScrollBehavior(context: Context, attrs: AttributeSet) : CoordinatorLayout.Behavior<FloatingActionMenu>() {
    private var acumulator = 0
    private var threshold = 0

    override fun onStartNestedScroll(coordinatorLayout: CoordinatorLayout, child: FloatingActionMenu, directTargetChild: View, target: View, axes: Int, type: Int): Boolean {
        threshold = (if (child.childCount > 0) child.getChildAt(0).height else child.height) / 2
        return true
    }

    override fun onNestedScroll(coordinatorLayout: CoordinatorLayout, child: FloatingActionMenu, target: View, dxConsumed: Int, dyConsumed: Int, dxUnconsumed: Int, dyUnconsumed: Int, type: Int) {
        super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, type)

        if ((acumulator * dyConsumed) < 0) { //scroll direction change
            acumulator = 0
        }
        acumulator += dyConsumed

        if (acumulator > threshold && !child.isMenuButtonHidden) {
            child.hideMenuButton(true)
        } else if (acumulator < -threshold && child.isMenuButtonHidden) {
            child.showMenuButton(true)
        }
    }

    override fun onStopNestedScroll(coordinatorLayout: CoordinatorLayout, child: FloatingActionMenu, target: View, type: Int) {
        super.onStopNestedScroll(coordinatorLayout, child, target, type)
        acumulator = 0
    }
}

then add this behavior to the FloatingActionMenu in your XML file using app:layout_behavior

AvatarQing commented 7 years ago

@fmrsabino Thanks for your improvement. I post it as java code here.


public class FabMenuBehavior extends CoordinatorLayout.Behavior<FloatingActionMenu> {

    private int accumulator = 0;
    private int threshold = 0;

    public FabMenuBehavior() {
        super();
    }

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

    @Override
    public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, FloatingActionMenu child, View directTargetChild, View target, int nestedScrollAxes) {
        threshold = (child.getChildCount() > 0 ? child.getChildAt(0).getHeight() : child.getHeight()) / 2;
        return true;
    }

    @Override
    public void onNestedScroll(CoordinatorLayout coordinatorLayout, FloatingActionMenu child, View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {
        super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed);
        if ((accumulator * dyConsumed) < 0) { //scroll direction change
            accumulator = 0;
        }
        accumulator += dyConsumed;

        if (accumulator > threshold && !child.isMenuButtonHidden()) {
            child.hideMenuButton(true);
        } else if (accumulator < -threshold && child.isMenuButtonHidden()) {
            child.showMenuButton(true);
        }
    }

    @Override
    public void onStopNestedScroll(CoordinatorLayout coordinatorLayout, FloatingActionMenu child, View target) {
        super.onStopNestedScroll(coordinatorLayout, child, target);
        accumulator = 0;
    }

}