RecyclerView快速滑动到顶部(源码分析)

RecyclerView提供了以下几个api控制RecyclerView滑动

SmoothScrollToPosition(int position) 按一定速度滚动到指定的位置

smoothScrollBy(int dx, int dy)   按一定速度滚动指定的距离

scrollToPosition(int position)   跳转到指定的位置

scrollBy(int dx,int dy)    跳转指定的距离

如果想做出像微信朋友圈双击滚动到顶部的那种效果,则需要使用smoothScrollToPosition(int position)这个方法

如果直接使用的时候,发现滚动速度太慢了,远远没有微信那种效果

那么我们这个时候要怎么修改才能加快滚动的速度呢

我们不妨来看一下smoothScrollToPosition这个方法的源码

public void smoothScrollToPosition(int position) {

    if (mLayoutFrozen) {

        return;

}

    if (mLayout == null) {

        Log.e(TAG, "Cannot smooth scroll without a LayoutManager set. " +

                "Call setLayoutManager with a non-null argument.");

        return;

}

    mLayout.smoothScrollToPosition(this, mState, position);

}

可以看到,里面是mLayout调用了smoothScrollToPosition这个方法,那么mLayout是什么呢


RecyclerView快速滑动到顶部(源码分析)_第1张图片
1
RecyclerView快速滑动到顶部(源码分析)_第2张图片
2

由上面两张图可以看出,mLayout就是RecyclerView调用setLayoutManager时传进来的LayoutManager;

我们再看LayoutManager里面的smoothScrollToPosition(int position)方法,此处选择LinearLayoutManager


RecyclerView快速滑动到顶部(源码分析)_第3张图片
3

我们可以看到,此处创建了一个LinearSmoothScroller,然后调用setTargetPosition(position)传进要滑动的位置,最后调用startSmoothScroll(linearSmoothScroller)开始滑动,那么滑动速度是在哪里设置的呢,我们接着看:

首先创建LinearSmoothScroller

4


RecyclerView快速滑动到顶部(源码分析)_第4张图片
5


6

可以看到Scroller的构造函数里面获取了MILLISECONDS_PER_PX这个值,再看calculateSpeedPerPixel这个方法,意思就是获取每个px滚动的速度,默认使用25f/displayMetrics.densityDpi计算,所以我们只要通过减少MILLISECONDS_PER_PX这个值就能提高滑动速度了

RecyclerView快速滑动到顶部(源码分析)_第5张图片
7

再看下MILLISECONDS_PER_PX这个值,这个是代表每个px的滚动时间,看下哪个方法用到,如图7所示

calculateTimeForScrolling(int dx)方法有使用,这个方法主要做的工作是把上面算的时间乘以总的滑动距离并返回,同时为了避免当dx非常小时,返回0的情况,做了浮点数向上取整的操作,所以我们还可以在这里通过修改dx或修改返回数值达到减少滑动时间的目的。

回到上面

linearSmoothScroller.setTargetPosition(position);

startSmoothScroll(linearSmoothScroller);

smoothScrollToPosition还剩下这两句代码

setTargetPosition的意思是传进目的位置,以后滑动的时候使用,然后startSmoothScroll(linearSmoothScroller)意思是调用linearSmoothScroller来进行滑动,那么具体的滑动算法就不详细分析了,有兴趣的人可以自己查看源码。

那么根据上面的结论,如果要修改滑动速度,那么新建一个LayoutManager,然后重写SmoothScrollToPosition,然后新建一个Scroller,在Scroller里面的calculateSpeedPerPixel或者calculateTimeForScrolling方法修改对应的参数即可修改成功

直接上代码

    public class FastScrollLinearLayoutManager extends LinearLayoutManager {

    private float MILLISECONDS_PER_INCH = 0.03f;

    private Context mContext;

    public FastScrollLinearLayoutManager(Contextcontext) {

        super(context);

        mContext=context;

        setSpeedFast();

    }

    /**

         * 慢滑

         */

    public void setSpeedSlow() {

        //自己在这里用density去乘,希望不同分辨率设备上滑动速度相同

        //0.3f是自己估摸的一个值,可以根据不同需求自己修改

        MILLISECONDS_PER_INCH = mContext.getResources().getDisplayMetrics().density * 0.3f;

        }


    /**

         * 快滑,滑动系数自己修改,这里选了一个比较顺眼的数值

         */

    public void setSpeedFast() {

        MILLISECONDS_PER_INCH=mContext.getResources().getDisplayMetrics().density*0.02f;

    }

    @Override

    public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position) {

        LinearSmoothScrollerlinear SmoothScroller = new LinearSmoothScroller(recyclerView.getContext()) {

        @Nullable

        @Override

        public PointF computeScrollVectorForPosition(int targetPosition) {

            return FastScrollLinearLayoutManager.this.computeScrollVectorForPosition(targetPosition);

        }

        // 控制滑动速度

        @Override

        protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) {

            // 单位速度 25F/densityDpi

            // return 1F / displayMetrics.densityDpi;

            return MILLISECONDS_PER_INCH / displayMetrics.density;

        }

        //该方法计算滑动所需时间。在此处间接控制速度。

        @Override

        protected intcalculateTimeForScrolling(intdx){

            /*

                  控制距离, 然后根据上面那个方(calculateSpeedPerPixel())提供的速度算出时间,

                  默认一次 滚动 TARGET_SEEK_SCROLL_DISTANCE_PX = 10000个像素,

                  在此处可以减少该值来达到减少滚动时间的目的.

                    */

            //间接计算时提高速度,也可以直接在calculateSpeedPerPixel提高

            //                if (dx > 3000) {

            //                    dx = 3000;

            //                }

                return super.calculateTimeForScrolling(dx);

        }

    };

    linearSmoothScroller.setTargetPosition(position);

    startSmoothScroll(linearSmoothScroller);

    }

}

你可能感兴趣的:(RecyclerView快速滑动到顶部(源码分析))