今天跟大家分享下RecyclerView怎么使它的条目自动滚动
其实做这个也是项目中有个需求需要用到,但是在网上找遍了也没有找到专门讲解这个知识点的文章。
所以这段时间自己研究懂了后 分享给大家。
再次更新下,找到了一个新的解决办法,那就是 RecyclerView 的smoothScrollToPosition
方法。其实这个方法之前用过,也是可以平滑滚动,但是速度太快,没办法自定义时间。所以就没有说 ,但是昨天晚上经过简友的提醒,我又细心的找了一遍,发现这个方法确实是可以改变时间的 而且不用像下面那么麻烦而且解决了所有问题,简直棒到没朋友,那么下面是解决方法。
[RecyclerView调用smoothScrollToPosition() 控制滑动速度]
一想到条目自动滚动,让我想起了ListView有一个方法叫做setSelection(int position)
可以设置一个位置 然后他就会自动滚动到指定的位置,但是现在这都什么年代了 果断抛弃了LisView 使用RecyclerView来做 至于RecyclerView有什么好处 为什么使用它 大家自行Google吧。
那么我们回到RecyclerView中想想该怎么实现这个呢 找了找RecyclerView中方法 发现有这么一个方法scrollToPosition(int position)
这个方法跟ListView的一样也是传入进去一位置 自动给你跳到指定的位置 ,这会儿 你可能心想 我去这不是直接就实现了么,但是 你用下看效果 那个条目跟瞬移是的 直接就干到最底部了! (如果你们产品能接受 那就当我没说) 既然这样不行 那就换,突然想到谷歌给我们提供了一个叫做Scroller的类 看描述!
Scroller是一个专门用于处理滚动效果的工具类,可能在大多数情况下,我们直接使用Scroller的场景并不多,但是很多大家所熟知的控件在内部都是使用Scroller来实现的,如ViewPager、ListView等。
不熟悉的可以看下这篇博客[Android Scroller完全解析,关于Scroller你所需知道的一切]
其实说到底他也就还是个工具类 也就是说其实最后能让Item滚动并不是他 这时候就要介绍下我们的另外两个方法 scrollTo()和scrollBy()这两个方法 这两个才是主角 就是这个两个方法才能让我们的View滑动 他们的使用也很简单 就是传入 一个x坐标 和一个 y坐标 他就会照着你给的位置去移动 他俩不一样的地方无非就是 scrollTo 是以当前View的初始位置开始移动 而scrollBy是根据当前位置来进行移动 而其他的特性大家也可以看上面的博客 这里就不絮叨了,
那么大家知道scrollTo()和scrollBy()的移动方式 就是移动他的内容 而不是他自己本身,那这里正好 我们不就是想移动RecyclerView的Item么?但是用过你会发现,我去,这家伙怎么跟之前用的那个设置位置移动的方法一个德行 ,也嗖的一下就干过去了 .不过他并不是移动到底 如果是上下滑动的话 是根据你的y值而决定的 。
那么下面就要用到Scroller这个类了
使用startScroll(int startX, int startY, int dx, int dy)
开始启动滑动 并且重写computeScroll()
方法完成值得过度 并且调用invalidate();
方法请求View数重新绘制 这个一定要记得调用 不要会没有效果
@Override public void computeScroll() { //重写computeScroll()方法,并在其内部完成平滑滚动的逻辑 if (mScroller.computeScrollOffset()) { scrollBy(mScroller.getCurrX(), mScroller.getCurrY()); invalidate(); } }
看下效果
使用后你会发现,哎确实是自动滚动了,而且也不是嗖的一下在就没了。 好像这样确实是已经实现了,但是如果我想让他滚动的在慢一点怎么办?或者说我想他的滚动速度是可以调的,那怎么办 ? 其实这个startScroll 还有一个重载的方法 startScroll(int startX, int startY, int dx, int dy, int duration)
可以再添加一个时间,单位是毫秒。
但是这里还有一个问题就是RecyclerView是不让使用scrollTo方法 如果使用了是没有效果的 而且还会打Log提醒
RecyclerView does not support scrolling to an absolute position "Use scrollToPosition instead
第二种方法
到现在就已经是实现RecyclerView 的自动滚动效果了,但是有没有其他方法可以实现呢?当然有 ,那就是使用属性动画来实现。
属性动画我们大家都知道,分为两种重要的类,分别为ValueAnimator 和 ObjectAnimator,ValueAnimator 就是来计算我们给的初始值和结束值说白了就是对值进行计算来完成数值之间的过度动画 ,而ObjectAnimator不仅会对值进行计算还会通过反射的方式把计算出来的值赋值给做动画对象的属性,这里我只是说个大概,但是你有没有发现其实之前的Scroller也是我们给个开始位置 和结束为止 他来给我们计算数值 然后我们在scrollBy过去 你会发现这个计算值的过程跟上面的ValueAnimator 是不是老像了? 好 那我们就来试试 看看行不行。
//默认从0-200 valueAnimator = ValueAnimator.ofInt(200); valueAnimator.setDuration(5000); valueAnimator.setInterpolator(new LinearInterpolator());valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override publicvoidonAnimationUpdate(ValueAnimatoranimation) { //获取估值器给我们的返回值 int animatedValue = (int) animation.getAnimatedValue(); //调用RecyclerView的scrollBy执行滑动 recyclerView.scrollBy(0, animatedValue); Log.e("TAG", "animatedValue:" + animatedValue); } } ); valueAnimator.start();
你会发现效果是一样一样的 ,但是实验到这里 我想悲哀的告诉大家,这里面有个Bug,细心的可能发现了,当我们不论是用上面那种方法,当你的Item内容比较少,而我们的结束值又是随便设置的,执行时间稍微长一点 你就会发现,哎?我怎么不能往上面滑动了,但等一会又可以滑动了,其实是这个scrollBy还没有执行完, 还在往下滑动,只不过是滑动到头了,你看不见罢了 ,那又怎么决解这个问题呢 ?其实RecyclerView有一个监听 addOnScrollListener 如果你没有这个方法 说明你该更新了RecyclerView了 这个监听有两个回掉。
- onScrollStateChanged 滑动状态 两个参数一个View 一个状态 分为按下滑动 和抬起 和MotionEvent 是一样的 。
- onScrolled 三个参数 View 和 x,y轴滑动的量。
其实通过这两个回掉很简单的就能解决这个问题 就是我们只要能判断出当前这个RecyclerView 是不是滑动到底部就行了 在onScrollStateChanged中判断? 当滑动的状态为抬起的时候我们判断 不行 因为我们是使用scrollBy方法进行的滑动 妹的 这个方法根本就不会执行 他只有你手指滑动的时候才会执行,那咋办 只有在onScrolled 中判断了 这个方法才不会管你什么滑动呢 只要我动了 他就执行 那怎判断呢?
(直接图片了 代码这个格式真心没弄好 怎么弄都不行 !)
大概的过程就是 ,我开始执行动画 ,然后不断判断是否达到最底部 ,不是得话就继续执行滑动。这时候呢,因为我监听了RecyclerVIew的滑动 一滑动我就判断。
怎么判断呢?得到当前显示的最后一个item的view,通过这个View 得到他的bottom坐标值,然后在获得RecyclerView的bottom坐标值,在拿到最后View的position,在拿到RecyclerView item的总数-1,他们四个进行比较。 都满足了,就能说明,当前已经滑动到最底部了,这时候给isBottom赋值为True ,接着动画监听里面我们之前不是做了判断么!满足else条件 取消动画,就不会在执行了,那个Bug也就解决了。
但是现在这个方法还有效率问题,滑动就执行判断,而且还是获取View的各种信息,想办法在优化吧。还有一个就是,如果我们能知道具体移动到什么位置就好了 ,我们上面设置的是200,因为这个参数是坐标,而RecyclerView的内容其实已经超过屏幕坐标系了,这个问题待解决。。。。
好了 以上就是我总结的一些开发中的经验 如果有谁能知道解决这个办法 和写的不对的地方 欢迎指教 。。。