之前总结了实现轮播图的各种方式.不过总的来说,基本都是通过viewpager来实现.并且效果也不能称为 完美 . 在IOS中,实现轮播图的方式更为丰富,什么两图轮播,三图轮播... 所以偶尔我也思考是否还有其它方式可以实现.
Google官方提供的可滑动控件无非就是ScrollView,ListView,RecyclerView等等. 其中RecyclerView就是专门处理视图回收的,那么是否可以使用RecyclerView来实现呢?
使用RecyclerView来轮播,首先需要解决两个问题
- 一次只能滑动一页
- 不能滑一半,每次停止的时候,都要让当前页居中显示
本来要实现这个功能是挺麻烦的,幸好在 RecyclerView-24.2.0(大概是)开始,新增了一个类可以帮助我们完成90%,那就是 LinearSnapHelper.
LinearSnapHelper的使用很简单:
new LinearSnapHelper().attachToRecyclerView(recyclerView);
只需要上面这行代码,RecyclerView就能实现类似ViewPager的功能,在滑动停止的时候,让某页居中显示.唯一的不同,就是RecyclerView一次可以滑动很多页.
其实这样就已经完全足够了,当然如果你一定想每次都只能滑动一页,那么就需要重写一下 LinearSnapHelper 的 findTargetSnapPosition 方法. findTargetSnapPosition 就是 LinearSnapHelper 通过当前滑动速度,计算最终定位position的方法.
private class PagerSnapHelper extends LinearSnapHelper {
@Override
public int findTargetSnapPosition(RecyclerView.LayoutManager layoutManager, int velocityX, int velocityY) {
int targetPos = super.findTargetSnapPosition(layoutManager, velocityX, velocityY);
final View currentView = findSnapView(layoutManager);
if(targetPos != RecyclerView.NO_POSITION && currentView != null){
int currentPostion = layoutManager.getPosition(currentView);
int first = ((LinearLayoutManager)layoutManager).findFirstVisibleItemPosition();
int last = ((LinearLayoutManager)layoutManager).findLastVisibleItemPosition();
currentPostion = targetPos < currentPostion ? last : (targetPos > currentPostion ? first : currentPostion);
targetPos = targetPos < currentPostion ? currentPostion - 1 : (targetPos > currentPostion ? currentPostion + 1 : currentPostion);
}
return targetPos;
}
}
在上面的代码中,稍微耍了点小心思,就是通过原来计算的结果,如果是往前滑动,那么就重新赋值为当前位置 - 1 ; 如果是往后滑动,那就则重新赋值为当前位置 + 1. 到这里,RecyclerView的效果就完全和ViewPager一致了.
因为RecyclerView内部完美的处理了视图的回收,所以实现轮播图的思路也就很明确了:
给适配器设置为无限大,
然后将初始位置通过 scrollToPosition() 定位在中间某个地方,完全不用担心像使用ViewPager一样的ANR问题,
-
通过定时器,每隔一定事件调用
// 向后翻动一页 recyclerView.smoothScrollToPosition(++currentIndex);
刷新的时候,通过 notifyDataSetChanged()更新数据,不用每次再重新设置适配器了.
其它的思路,就和 全面总结轮播图 中的最终方式一样了,这里不再重复.
效果也和之前非常类似: