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

作者: baiaj | 来源:发表于2018-05-24 17:35 被阅读182次

    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是什么呢

    1 2

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

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

    3

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

    首先创建LinearSmoothScroller

    4 5 6

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

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

        }

    }

    相关文章

      网友评论

      • 大叔top:我喜欢你的壁纸和主题
        大叔top:@baiaj 多谢多谢
        baiaj:@大叔top 哈哈,主题你在http://color-themes.com/?view=index这个链接找就好了,壁纸的话百度搜一下tara就有了

      本文标题:RecyclerView快速滑动到顶部(源码分析)

      本文链接:https://www.haomeiwen.com/subject/provmttx.html