自定义Behavior实现快速返回效果

利用recyclerView的上下滑动来使FloatingActionButton显示或隐藏,点击FloatingActionButton使recyclerView快速滑动到顶部。

实现这个这个功能,主要涉及三个知识点,悬浮按钮(FloatingActionButton),自定义Behavior,以及解析并解决sdk25以上FloatingActionButton只隐藏不显示的问题。

本次开发环境基于sdk25。

使用之前要先引入design包

compile ‘com.android.support:design:25.3.1’

悬浮按钮(FloatingActionButton)

<android.support.design.widget.FloatingActionButton
        android:id="@+id/contact_fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|right"
        android:layout_margin="10dp"
        android:src="@mipmap/ic_launcher"
        app:backgroundTint="@color/gray"
        app:backgroundTintMode="multiply"
        app:borderWidth="0dp"
        app:elevation="@dimen/activity_horizontal_margin"
        app:fabSize="auto"
        app:pressedTranslationZ="@dimen/activity_horizontal_margin"
        app:rippleColor="@color/gray"
        app:useCompatPadding="true" />

app:backgroundTint 按钮的背景颜色,不设置,默认使用theme中colorAccent的颜色。

app:backgroundTintMode 按钮背景颜色的模式,在设置screen的时候就跟其他模式有点区别,区别在颜色变了,其他不变,具体不详,可忽略。

app:borderWidth 该属性如果不设置0dp,那么在4.1的sdk上FAB会显示为正方形,而且在5.0以后的sdk没有阴影效果。所以设置为borderWidth=”0dp”。

app:elevation 默认状态下阴影大小。

app:fabSize 设置大小,该属性有两个值,分别为normal和mini,对应的大小分别为56dp和40dp。

app:pressedTranslationZ 按钮按下去的状态下的阴影大小。

扫描二维码关注公众号,回复: 949157 查看本文章

app:rippleColor 设置点击时的背景颜色。

app:useCompatPadding 是否使用兼容的填充大小。

Behavior介绍

Behavior是Android Design包中出现的一个概念,Android Design包中很多控件的动画效果都是使用Behavior实现的,所以想要更好的实现Material Design风格的应用就有必要弄清楚Behavior。

先看官方介绍
https://developer.android.google.cn/reference/android/support/design/widget/CoordinatorLayout.Behavior.html

这里写图片描述

上面的介绍说Behavior是CoordinatorLayout子视图的一个交互插件,它可以为子视图实现一个或多个交互,这些交互包括拖拽,滑动或其他的手势操作。

通过上面的介绍我们知道Behavior是作用于CoordinatorLayout子视图的,而CoordinatorLayout我们可以把它看做一个FrameLayout。

Behavior相关方法

public class BackTopBehavior extends CoordinatorLayout.Behavior {
    public MyBehavior(Context context, AttributeSet attrs) {
        super(context, attrs);
        //必须实现此构造方法,因为CoordinatorLayout中初始化Behavior时是通过反射调用此构造来进行初始化的
    }

    @Override
    public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {
        return super.layoutDependsOn(parent, child, dependency);
        //判断视图child进行layout布局时是否依赖于某个特定的View dependency
        //child是指应用此Behavior的View,dependency是触发执行此Behavior的视图并与child进行相关交互,也就是上面所说的是child的依赖
        //此方法在CoordinatorLayout进行request layout时至少会调用一次
        //如果返回true,CoordinatorLayout会总是在依赖视图dependency layout完成之后对child视图进行layout布局
        //同时如果依赖视图dependency的layout或position发生变化,CoordinatorLayout会调用onDependentViewChanged
    }

    @Override
    public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {
        return super.onDependentViewChanged(parent, child, dependency);
        //此方法的调用时机参考上面的方法layoutDependsOn的说明
        //当child的依赖视图dependency发生layout变化后,如果想对child布局(child's size or position)做出相应变化则返回true否则返回false,具体对child如何update则需要在onLayoutChild中进行实现
    }

    @Override
    public void onDependentViewRemoved(CoordinatorLayout parent, View child, View dependency) {
        super.onDependentViewRemoved(parent, child, dependency);
        //当child的依赖视图dependency从其parent中remove掉后会调用此方法
    }

    @Override
    public boolean onMeasureChild(CoordinatorLayout parent, View child, int parentWidthMeasureSpec, int widthUsed, int parentHeightMeasureSpec, int heightUsed) {
        return super.onMeasureChild(parent, child, parentWidthMeasureSpec, widthUsed, parentHeightMeasureSpec, heightUsed);
        //当测量CoordinatorLayout的子视图child时调用此方法
    }

    @Override
    public boolean onLayoutChild(CoordinatorLayout parent, View child, int layoutDirection) {
        return super.onLayoutChild(parent, child, layoutDirection);
        //当对CoordinatorLayout的子视图child进行layout布局时会调用此方法
        //当child的依赖视图layout结束之后,会调用此方法对child进行layout布局
        //如果onDependentViewChanged中返回了true,则需要在此方法中对child视图进行update
    }

    @Override
    public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, View child, View directTargetChild, View target, int nestedScrollAxes) {
        return super.onStartNestedScroll(coordinatorLayout, child, directTargetChild, target, nestedScrollAxes);
        //滑动开始调用,返回true表示此Behavior接收此滑动,才会有后续的滑动处理
    }

    @Override
    public void onStopNestedScroll(CoordinatorLayout coordinatorLayout, View child, View target) {
        super.onStopNestedScroll(coordinatorLayout, child, target);
        //滑动结束调用
    }

    @Override
    public void onNestedScroll(CoordinatorLayout coordinatorLayout, View child, View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {
        super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed);
        //滑动过程中调用
    }

    @Override
    public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, View child, View target, int dx, int dy, int[] consumed) {
        super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed);
       //滑动过程中,在child自身消费掉此次滑动的distance之前调用此方法
       //onNestedPreScroll is called each time the nested scroll is updated by the nested scrolling child
       // before the nested scrolling child has consumed the scroll distance itself
    }

    @Override
    public boolean onNestedFling(CoordinatorLayout coordinatorLayout, View child, View target, float velocityX, float velocityY, boolean consumed) {
        return super.onNestedFling(coordinatorLayout, child, target, velocityX, velocityY, consumed);
        //快速滑动时调用此方法
    }
}

上面就是Behavior中比较常用比较重要的一些方法。

使用

布局

<?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:orientation="vertical">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/contact_recyclerview"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">

    </android.support.v7.widget.RecyclerView>

    <android.support.design.widget.FloatingActionButton
        android:id="@+id/contact_fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|end"
        android:layout_margin="10dp"
        android:src="@mipmap/ic_launcher"
        app:backgroundTint="@color/turquoise"
        app:borderWidth="0dp"
        app:elevation="0dp"
        app:fabSize="auto"
        app:pressedTranslationZ="50dp"
        app:rippleColor="@color/gray"
       app:layout_behavior="com.voctex.ui.tablayout.other.ScrollingViewBehavior" />


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

在以上布局中,需要在xml中为fab指定一个属性,就可以实现recyclerView在上下滑动时fab的显示或隐藏了。

app:layout_behavior="com.voctex.ui.tablayout.other.ScrollingViewBehavior"

而这个值就是自定义Behavior,继承于FloatingActionButton.Behavior,重写onStartNestedScroll和onNestedScroll这两个方法,相关代码如下:

package com.voctex.ui.tablayout.other;

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.view.View;

/**
 * Created by mac_xihao on 17/7/3.
 * 返回顶部 的behavior
 * Behavior只有是CoordinatorLayout的直接子View才有意义
 */
public class ScrollingViewBehavior extends FloatingActionButton.Behavior {

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

    /**
     * 处理垂直方向上的滚动事件
     *
     * @param coordinatorLayout
     * @param child
     * @param directTargetChild
     * @param target
     * @param nestedScrollAxes
     * @return
     */
    @Override
    public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, FloatingActionButton child, View directTargetChild, View target, int nestedScrollAxes) {
        // Ensure we react to vertical scrolling
        return nestedScrollAxes == ViewCompat.SCROLL_AXIS_VERTICAL ||
                super.onStartNestedScroll(coordinatorLayout, child, directTargetChild, target,
                        nestedScrollAxes);
    }

    /**
     * 检查Y的位置,并决定按钮是否动画进入或退出
     *
     * @param coordinatorLayout
     * @param child
     * @param target
     * @param dxConsumed
     * @param dyConsumed
     * @param dxUnconsumed
     * @param dyUnconsumed
     */
    @Override
    public void onNestedScroll(CoordinatorLayout coordinatorLayout, FloatingActionButton child, View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {
        super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed,
                dyUnconsumed);

        if (dyConsumed > 10 && child.getVisibility() == View.VISIBLE) {
            // User scrolled down and the FAB is currently visible -> hide the FAB
            //执行隐藏的动画
            child.hide();
        } else if (dyConsumed < -10 && child.getVisibility() != View.VISIBLE) {
            // User scrolled up and the FAB is currently not visible -> show the FAB
            //执行显示的动画
            child.show();
        }
    }
}

其实,到这里是应该结束的了,实现起来是很简单的,但是我在测试的时候却发现了一个比较坑的问题,就是RecylerView在滑动的时候,只能隐藏,却不显示fab。

解析并解决sdk25 FloatingActionButton只隐藏不显示的问题

sdk25以上,CoordinatorLayout的onNestedScroll方法会多出一段代码

 @Override
    public void onNestedScroll(View target, int dxConsumed, int dyConsumed,
            int dxUnconsumed, int dyUnconsumed) {
        final int childCount = getChildCount();
        boolean accepted = false;

        for (int i = 0; i < childCount; i++) {
            final View view = getChildAt(i);
            //sdk25以上会多出这个判断
            if (view.getVisibility() == GONE) {
                // If the child is GONE, skip...
                continue;
            }

            final LayoutParams lp = (LayoutParams) view.getLayoutParams();
            if (!lp.isNestedScrollAccepted()) {
                continue;
            }

            final Behavior viewBehavior = lp.getBehavior();
            if (viewBehavior != null) {
                viewBehavior.onNestedScroll(this, view, target, dxConsumed, dyConsumed,
                        dxUnconsumed, dyUnconsumed);
                accepted = true;
            }
        }

        if (accepted) {
            onChildViewsChanged(EVENT_NESTED_SCROLL);
        }
    }

也就是CoordinatorLayout在滑动的时候,判断子view是否被设置为GONE,如果是,直接执行下一次循环,然后就不回调onNestedScroll,而我们自定义的那个类的onNestedScroll方法就不走了。

而在fab执行hide方法的时候,默认是把fab设置为GONE的,我们来看看fab中的hide方法:

 /**
     * Hides the button.
     * <p>This method will animate the button hide if the view has already been laid out.</p>
     */
    public void hide() {
        hide(null);
    }

    /**
     * Hides the button.
     * <p>This method will animate the button hide if the view has already been laid out.</p>
     *
     * @param listener the listener to notify when this view is hidden
     */
    public void hide(@Nullable OnVisibilityChangedListener listener) {
        hide(listener, true);
    }

    void hide(@Nullable OnVisibilityChangedListener listener, boolean fromUser) {
        getImpl().hide(wrapOnVisibilityChangedListener(listener), fromUser);
    }

最后是调用了以下代码,并且fromUser默认为true,这个值很关键

getImpl().hide(wrapOnVisibilityChangedListener(listener), fromUser);

接下来我们继续走下去,getImpl()是获得哪个对象

private FloatingActionButtonImpl getImpl() {
        if (mImpl == null) {
            mImpl = createImpl();
        }
        return mImpl;
    }

    private FloatingActionButtonImpl createImpl() {
        final int sdk = Build.VERSION.SDK_INT;
        if (sdk >= 21) {
            return new FloatingActionButtonLollipop(this, new ShadowDelegateImpl(),
                    ViewUtils.DEFAULT_ANIMATOR_CREATOR);
        } else if (sdk >= 14) {
            return new FloatingActionButtonIcs(this, new ShadowDelegateImpl(),
                    ViewUtils.DEFAULT_ANIMATOR_CREATOR);
        } else {
            return new FloatingActionButtonGingerbread(this, new ShadowDelegateImpl(),
                    ViewUtils.DEFAULT_ANIMATOR_CREATOR);
        }
    }

在这里我们默认用4.0以上的手机进行测试,所以获得的对象是FloatingActionButtonIcs的实例,然后就进入看看它的hide方法是如何实现的。

@Override
    void hide(@Nullable final InternalVisibilityChangedListener listener, final boolean fromUser) {
        if (isOrWillBeHidden()) {
            // We either are or will soon be hidden, skip the call
            return;
        }

        mView.animate().cancel();

        if (shouldAnimateVisibilityChange()) {
            mAnimState = ANIM_STATE_HIDING;

            mView.animate()
                    .scaleX(0f)
                    .scaleY(0f)
                    .alpha(0f)
                    .setDuration(SHOW_HIDE_ANIM_DURATION)
                    .setInterpolator(AnimationUtils.FAST_OUT_LINEAR_IN_INTERPOLATOR)
                    .setListener(new AnimatorListenerAdapter() {
                        private boolean mCancelled;

                        @Override
                        public void onAnimationStart(Animator animation) {
                            mView.internalSetVisibility(View.VISIBLE, fromUser);
                            mCancelled = false;
                        }

                        @Override
                        public void onAnimationCancel(Animator animation) {
                            mCancelled = true;
                        }

                        @Override
                        public void onAnimationEnd(Animator animation) {
                            mAnimState = ANIM_STATE_NONE;

                            if (!mCancelled) {
                                mView.internalSetVisibility(fromUser ? View.GONE : View.INVISIBLE,
                                        fromUser);
                                if (listener != null) {
                                    listener.onHidden();
                                }
                            }
                        }
                    });
        } else {
            // If the view isn't laid out, or we're in the editor, don't run the animation
            mView.internalSetVisibility(fromUser ? View.GONE : View.INVISIBLE, fromUser);
            if (listener != null) {
                listener.onHidden();
            }
        }
    }

直接看onAnimationEnd方法里面,默认fromUser为true,所以在这里fab是直接被设置为了Gone,而CoordinatorLayout的onNestedScroll方法里的循环又判断子view为Gone的时候直接跳出执行下次循环,这里是很矛盾的。

那么在什么情况下fromUser为false呢?

因为hide(@Nullable OnVisibilityChangedListener listener, boolean fromUser)方法访问权限为default,只有同个包里面的类才能调用,我直接搜索了fab这个方法的调用,发现了还有两个方法调用了这个方法,分别是:

private boolean updateFabVisibilityForAppBarLayout(CoordinatorLayout parent,
                AppBarLayout appBarLayout, FloatingActionButton child) {
            if (!shouldUpdateVisibility(appBarLayout, child)) {
                return false;
            }

            if (mTmpRect == null) {
                mTmpRect = new Rect();
            }

            // First, let's get the visible rect of the dependency
            final Rect rect = mTmpRect;
            ViewGroupUtils.getDescendantRect(parent, appBarLayout, rect);

            if (rect.bottom <= appBarLayout.getMinimumHeightForVisibleOverlappingContent()) {
                // If the anchor's bottom is below the seam, we'll animate our FAB out
                child.hide(mInternalAutoHideListener, false);
            } else {
                // Else, we'll animate our FAB back in
                child.show(mInternalAutoHideListener, false);
            }
            return true;
        }


        private boolean updateFabVisibilityForBottomSheet(View bottomSheet,
                FloatingActionButton child) {
            if (!shouldUpdateVisibility(bottomSheet, child)) {
                return false;
            }
            CoordinatorLayout.LayoutParams lp =
                    (CoordinatorLayout.LayoutParams) child.getLayoutParams();
            if (bottomSheet.getTop() < child.getHeight() / 2 + lp.topMargin) {
                child.hide(mInternalAutoHideListener, false);
            } else {
                child.show(mInternalAutoHideListener, false);
            }
            return true;
        }

可以发现,这两个类里面,hide的方法都是传入false的,还有,从名字可以发现,这两个方法应该分别是针对AppBarLayout和BottomSheet的,访问权限是私有的,所以可以继续在fab类里面搜索调用的地方,发现这两个方法,都在另外两个方法里面一起被调用了

@Override
        public boolean onDependentViewChanged(CoordinatorLayout parent, FloatingActionButton child,
                View dependency) {
            if (dependency instanceof AppBarLayout) {
                // If we're depending on an AppBarLayout we will show/hide it automatically
                // if the FAB is anchored to the AppBarLayout
                updateFabVisibilityForAppBarLayout(parent, (AppBarLayout) dependency, child);
            } else if (isBottomSheet(dependency)) {
                updateFabVisibilityForBottomSheet(dependency, child);
            }
            return false;
        }
@Override
        public boolean onLayoutChild(CoordinatorLayout parent, FloatingActionButton child,
                int layoutDirection) {
            // First, let's make sure that the visibility of the FAB is consistent
            final List<View> dependencies = parent.getDependencies(child);
            for (int i = 0, count = dependencies.size(); i < count; i++) {
                final View dependency = dependencies.get(i);
                if (dependency instanceof AppBarLayout) {
                    if (updateFabVisibilityForAppBarLayout(
                            parent, (AppBarLayout) dependency, child)) {
                        break;
                    }
                } else if (isBottomSheet(dependency)) {
                    if (updateFabVisibilityForBottomSheet(dependency, child)) {
                        break;
                    }
                }
            }
            // Now let the CoordinatorLayout lay out the FAB
            parent.onLayoutChild(child, layoutDirection);
            // Now offset it if needed
            offsetIfNeeded(parent, child);
            return true;
        }

也就是说,只有在(AppBarLayout或者BottomSheet)与fab同为兄弟布局的时候,然后在他们滑动的时候,fab才会正常显示和隐藏,那么其他布局怎么办?像RecyclerView这种情况下该怎么解决?

其实也很简单,只要不执行hide方法,自己实现隐藏动画,也不要使用setVisibility(GONE),可以使用setVisibility(INVISIBLE)。我这里直接拿了fab隐藏的动画,进行了修改了一下,然后就变成了我自己的,接下来直接贴代码好了。

package com.voctex.ui.tablayout.other;

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.view.View;

/**
 * Created by mac_xihao on 17/7/3.
 * 返回顶部 的behavior
 * Behavior只有是CoordinatorLayout的直接子View才有意义
 */
public class ScrollingViewBehavior extends FloatingActionButton.Behavior {

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

    /**
     * 处理垂直方向上的滚动事件
     *
     * @param coordinatorLayout
     * @param child
     * @param directTargetChild
     * @param target
     * @param nestedScrollAxes
     * @return
     */
    @Override
    public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, FloatingActionButton child, View directTargetChild, View target, int nestedScrollAxes) {
        // Ensure we react to vertical scrolling
        return nestedScrollAxes == ViewCompat.SCROLL_AXIS_VERTICAL ||
                super.onStartNestedScroll(coordinatorLayout, child, directTargetChild, target,
                        nestedScrollAxes);
    }

    /**
     * 检查Y的位置,并决定按钮是否动画进入或退出
     *
     * @param coordinatorLayout
     * @param child
     * @param target
     * @param dxConsumed
     * @param dyConsumed
     * @param dxUnconsumed
     * @param dyUnconsumed
     */
    @Override
    public void onNestedScroll(CoordinatorLayout coordinatorLayout, FloatingActionButton child, View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {
        super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed,
                dyUnconsumed);

        if (dyConsumed > 10 && child.getVisibility() == View.VISIBLE) {
            // User scrolled down and the FAB is currently visible -> hide the FAB
            //上滑中
            //执行隐藏的动画
            AnimotionUtils.onHide(child);
        } else if (dyConsumed < 0 && child.getVisibility() != View.VISIBLE) {
            // User scrolled up and the FAB is currently not visible -> show the FAB
             //下滑中
            //执行显示的动画
           AnimotionUtils.onShow(child);
        }
    }


public static <V extends View> FabBehavior from(V view) {
        ViewGroup.LayoutParams params = view.getLayoutParams();
        if (!(params instanceof CoordinatorLayout.LayoutParams)) {
            throw new IllegalArgumentException("The view is not a child of CoordinatorLayout");
        }
        CoordinatorLayout.Behavior behavior = ((CoordinatorLayout.LayoutParams) params).getBehavior();
        if (!(behavior instanceof FabBehavior)) {
            throw new IllegalArgumentException("The view is not associated with FabBehavior");
        }
        return (FabBehavior) behavior;
    }

}

AnimotionUtils:

public class AnimotionUtils {

    /**
     * 隐藏动画
     * @param fab
     */
    public static void onHide(FloatingActionButton fab){
        ViewCompat.animate(fab).scaleX(0f).scaleY(0f).start();
        fab.setVisibility(View.INVISIBLE);
    }

    public static void onShow(FloatingActionButton fab){
        fab.setVisibility(View.VISIBLE);
        ViewCompat.animate(fab).scaleX(1f).scaleY(1f).start();
    }
}

代码实现:

public class EndlessLinearLayoutActivity extends AppCompatActivity implements View.OnClickListener {
@BindView(R.id.line_recycler)
RecyclerView lineRecycler;
@BindView(R.id.fab_back_to_top)
FloatingActionButton fabBackToTop;

private LinearLayoutManager mLinearLayoutManager;
private ScrollingViewBehavior fabBehavior;

private int mScrollHight = 0;//向上滚动的高度
private int mScreenHight = 0;//屏幕高度

 @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.endless_linearlayout_activity);
        ButterKnife.bind(this);
        initRecyclerView();
        initBehavior();
        //解决默认不置顶
        lineRecycler.setFocusable(false);
        setListener();
    }


private void initRecyclerView() {
        List<String> dataList = new ArrayList<>();
        for (int i = 0; i < 30; i++) {
            mList.add("位置为:"+i);
        }

        mLinearLayoutManager = new LinearLayoutManager(this);
        lineRecycler.setLayoutManager(mLinearLayoutManager);
        adapter = new EndlessLinearLayoutAdapter(this, dataList);
        lineRecycler.setAdapter(adapter);
    }


private void initBehavior(){
        fabBehavior = ScrollingViewBehavior.from(fabBackToTop);
        mScreenHight = ScreenUtils.getScreenHeight(this);
    }


/**
     * 监听事件
     */
    private void setListener() {
        fabBackToTop.setOnClickListener(this);

        lineRecycler.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                super.onScrollStateChanged(recyclerView, newState);
            }

            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);
                mScrollHight += dy;
                //如果有加载更多的功能,当下滑到第一页的时候,使fab隐藏
                if(mScrollHight < mScreenHight){//保证第一页不会出现
                    AnimotionUtils.onHide(fabBackToTop);
                }
            }
        });
    }


@Override
    public void onClick(View v) {
        switch (v.getId()){
                mLinearLayoutManager.scrollToPosition(0);
                AnimotionUtils.onHide(fabBackToTop);
                mScrollHight = 0;
                break;
            default:
                break;
        }

    }
}

http://m.blog.csdn.net/chen_xi_hao/article/details/74347023

猜你喜欢

转载自blog.csdn.net/qq_24382363/article/details/78689011