前言:

使用RecyclerView时,调用smoothScrollToPostion()方法滑动到指定位置,但是条目很多时滑动的很慢,本篇文章就是实现RecyclerView的快速滑动。

先介绍如何实现,然后再介绍原理。

1. 实现代码

  1. 创建FastScrollLinearLayoutManager,继承LinearLayoutManager
  2. 复写smoothScrollToPosition()方法,主要复写LinearSmoothScroller中方法

代码如下,解释全在注释中:

public class FastScrollLinearLayoutManager extends LinearLayoutManager {public FastScrollLinearLayoutManager(Context context) {super(context);}@Overridepublic void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position) {LinearSmoothScroller linearSmoothScroller = new LinearSmoothScroller(recyclerView.getContext()) {@Override public PointF computeScrollVectorForPosition(int targetPosition) {return  FastScrollLinearLayoutManager.this.computeScrollVectorForPosition(targetPosition);}//该方法控制速度。//if returned value is 2 ms, it means scrolling 1000 pixels with LinearInterpolation should take 2 seconds.@Override protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) {/*控制单位速度,  毫秒/像素, 滑动1像素需要多少毫秒.默认为 (25F/densityDpi) 毫秒/像素mdpi上, 1英寸有160个像素点, 25/160,xxhdpi,1英寸有480个像素点, 25/480,*///return 10F / displayMetrics.densityDpi;//可以减少时间,默认25Freturn super.calculateSpeedPerPixel(displayMetrics);}//该方法计算滑动所需时间。在此处间接控制速度。//Calculates the time it should take to scroll the given distance (in pixels)@Override protected int calculateTimeForScrolling(int dx) {/*控制距离, 然后根据上面那个方(calculateSpeedPerPixel())提供的速度算出时间,默认一次 滚动 TARGET_SEEK_SCROLL_DISTANCE_PX = 10000个像素,在此处可以减少该值来达到减少滚动时间的目的.*///间接计算时提高速度,也可以直接在calculateSpeedPerPixel提高if (dx > 3000) {dx = 3000;}int time = super.calculateTimeForScrolling(dx);LogUtil.d(time);//打印时间看下return time;}};linearSmoothScroller.setTargetPosition(position);startSmoothScroll(linearSmoothScroller);}
}

从复写的两个方法可以看出,都是为了提高滑动速度。一种是直接修改速度,另外一种是通过减少距离来减少所需时间,间接提高滑动速度。

这两种方法都可以,看自己所需。接下来就讲讲实现的原理。这块我只是梳理的大致的流程,不过至此你已经可以实现快速滑动了。

2. RecyclerView 滑动过程梳理

1.调用RecyclerView.smoothScrollToPosition(position)时

public void smoothScrollToPosition(int position) {//...直接调用了LayoutManager的该方法mLayout.smoothScrollToPosition(this, mState, position);}

2.LinearLayoutManager中

@Overridepublic void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state,int position) {LinearSmoothScroller linearSmoothScroller = new  LinearSmoothScroller(recyclerView.getContext()) {//...};//设置终点位置linearSmoothScroller.setTargetPosition(position);//开始滚动,使用LinearSmoothScroller(一直匀速滑动,当targetPosition出现在屏幕上时再减速滑动),startSmoothScroll()是LayoutManager中的方法startSmoothScroll(linearSmoothScroller);}

3.LayoutManager中

public void startSmoothScroll(SmoothScroller smoothScroller) {//...mSmoothScroller = smoothScroller;//调用SmoothScroller.start()方法开始滚动,this参数指当前LayoutManagermSmoothScroller.start(mRecyclerView, this);
}

4.SmoothScroller中

void start(RecyclerView recyclerView, LayoutManager layoutManager) {//...//使用ViewFlinger进行动画,ViewFlinger实现了Runnable接口,并且内部使用了Scroller,这样就可以post自己进而对RecyclerView不断layout就可以实现滑动mRecyclerView.mViewFlinger.postOnAnimation();
}

5.ViewFlinger中,这是实现滑动的重点,省略了很多代码逻辑

private class ViewFlinger implements Runnable {@Overridepublic void run() {if (scroller.computeScrollOffset()) {//调用SmoothScroller的onAnimation方法smoothScroller.onAnimation(dx - overscrollX, dy - overscrollY);}}
}

6.SmoothScroller中

private void onAnimation(int dx, int dy) {//...if (mTargetView != null) {// verify target positionif (getChildPosition(mTargetView) == mTargetPosition) {//要滑动到的位置已经显示在屏幕上,onTargetFound()方法里update了差值器,由线性差值器变成了减速的差值器。onTargetFound(mTargetView, recyclerView.mState, mRecyclingAction);mRecyclingAction.runIfNecessary(recyclerView);}//...if (mRunning) {//再下一次滑动onSeekTargetStep(dx, dy, recyclerView.mState, mRecyclingAction);//调用内部类Action的runIfNecessary方法mRecyclingAction.runIfNecessary(recyclerView);}}

7.Action中

private void runIfNecessary(RecyclerView recyclerView) {//调用了ViewFlinger.smoothScrollBy()方法,并传入了mDuration,mDuration是在SmoothScroller中upDate()时传入的,就是由前文讲的两个方法共同决定的recyclerView.mViewFlinger.smoothScrollBy(mDx, mDy, mDuration, mInterpolator);
}

8.ViewFlinger中开始滚动

public void smoothScrollBy(int dx, int dy, int duration, Interpolator interpolator) {if (mInterpolator != interpolator) {mInterpolator = interpolator;mScroller = ScrollerCompat.create(getContext(), interpolator);}setScrollState(SCROLL_STATE_SETTLING);mLastFlingX = mLastFlingY = 0;//调用Scroller开始滚动,此处即durationmScroller.startScroll(0, 0, dx, dy, duration);postOnAnimation();}

这块粗略的按照流程说了一下滚动过程,涉及的类比较多,最终通过Scroller来进行滚动。

结语:

本篇文章实现了RecyclerView的快速滚动,但需要注意一个问题:如果你的Item比较复杂,滚动起来会卡顿。 这个在看源码时的一个注释里面有提到,后来实践时确实也发现。不得不说微信朋友圈滑动起来的真的快,它用的是ListView,貌似开启了FastEnable属性。
同时也可以仿照知乎,先使用RecyclerView.scrollToPosition(position)直接滑动到某一个位置后再使用smoothScrollToPosition(0)滑动到顶部。这块在RecyclerView里的Action类中jumpTo()的注释里有提到,如果很远的话可以先到一个位置后再滑动。

这两种滑动到顶部的方式都实现了一个小Demo。测试代码在GitHub上 FastScrollFragment 。
另外在自己写的小项目上也用上了 ZhihuDaily,可以查看这两个Demo来具体了解。

Android RecyclerView 实现快速滑动相关推荐

  1. Android RecyclerView 监听滑动

    今天,简单讲讲Android 如何监听滑动. 不废话了,主要是需要做一个功能,实现RecyclerView滑动时,让一个标题栏固定显示在顶部. 基本知识: 列表的滚动一般分为两种: 手指按下 -> ...

  2. Android RecyclerView使用 及 滑动时加载图片优化方案

    1.控制线程数量 + 数据分页加载2.重写onScrollStateChanged方法 这个我们后面再谈,下面先来看看RecyclerView控件的使用及我们为什么选择使用它 RecyclerView ...

  3. android recyclerview监听滑动状态

    mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {@Overridepublic void onScroll ...

  4. android 快速 顶部,Android RecyclerView 快速滑到顶部

    前言: 使用RecyclerView时,调用smoothScrollToPostion()方法滑动到指定位置,但是条目很多时滑动的很慢,本篇文章就是实现RecyclerView的快速滑动. 先介绍如何 ...

  5. 【Android 手势冲突】Colin带你彻底解决RecyclerView与ScrollView滑动冲突问题,并实现RecyclerView悬停导航栏(附demo哦)

    在新一期的需求中,产品要求我们做出和美团某个页面类似的功能,即一个页面包含在scrollView中,上面一个部分放置一些常用的广告banner.宫格tab等,下面放置一个RecyclerView用于展 ...

  6. Android RecyclerView(九)滑动监听综述

    Android RecyclerView(九)滑动监听 1 RecyclerView 的滑动监听 1.1 RecyclerView 设置滑动监听 mRecyclerView.setOnScrollLi ...

  7. Android:RecyclerView滑动到边缘时的光晕效果

    相信大家对于RecyclerView 都已经不再陌生,我们都知道RecyclerView等可滑动控件默认的是会有滚动条以及滑动到边缘时的阴影(光晕)效果的,那么怎样去掉这两个默认属性呢,在这里简单的记 ...

  8. RecyclerView使用 及 滑动时加载图片优化方案

    RecyclerView使用 及 滑动时加载图片优化方案 简述 本篇博文主要给大家分享关于RecyclerView控件的使用及通过继承RecyclerView来实现滑动时加载图片的优化方案,也同样能解 ...

  9. Android Tv版嵌套滑动实现极光云视听顶部导航效果

    Android Tv版嵌套滑动实现极光云视听顶部导航效果 通过这篇文章您可以和小王一起: 了解嵌套滑动的流程,原理 自定义Behavior的原理. 简单的实现TV版的嵌套滑动 小王最近很开心,上次快速 ...

最新文章

  1. jsonp跨域访问服务
  2. 通过声明Attribute属性改变不同类的输出效果
  3. java new 删除吗,java泛型对象初始化-java泛型对象会实例化吗T t=new T()
  4. Mac OS 下 NVM 的安装与使用
  5. php字符串综合作业,0418php字符串的操作
  6. 存储过程的版本控制(StoreProcedure,SourceSafe)
  7. 10 条真心有趣的 Linux 命令
  8. latex表插入的位置不对_VSCode_LaTex_英文amp;中文配置
  9. 从零开始学ios开发(十三):Table Views(下)Grouped and Indexed Sections
  10. Kubernetes 学习2 k8s基础概念
  11. 第六章例题二叉树层次遍历
  12. [JLOI2008] CODES
  13. 第一次读 “Clean” 系列,并没有觉得这是一本多好的书
  14. MySQL曹操外卖项目--数据库设计
  15. 6款反垃圾邮件产品横向比较测试
  16. 电脑如何共享无线网络wifi给手机、其他电脑
  17. Js Switch语句
  18. 7-6 福到了 (15分)
  19. 万字长文带你玩转2020全国大学生计算机技能应用大赛—C语言模考整理解析
  20. HQChart使用教程11-如何把K线数据API替换成自己的API数据

热门文章

  1. px rpx pt em rem单位
  2. 首席新媒体运营黎想教程:3步教你如何做好社群运营
  3. 运作团购渠道,如何寻找团购客户(四)?
  4. Django邮件应用--QQ邮箱、网易邮箱(一)
  5. 详解坐标变换矩阵 - 绕 x 轴旋转的旋转矩阵
  6. oracle中对于TableSpace理解
  7. SQL面试题整理_数据库知识点
  8. 2018最新微信小程序经典案例开发视频教程合集
  9. windows搭建RN环境
  10. gcc与cmake、qmake与make、ninja