Android如何使用RecyclerView打造首页轮播图

Android如何使用RecyclerView打造首页轮播图,第1张

概述先看看效果图:停在中间自动翻页序言:最近接到一个任务,做一个类似上面自动翻页的功能。可以看到,这一屏中有三张图片显示出来了,有两张没有显示完全,看到设计图的时候第一反应是可以用viewpager来实现,但是

先看看效果图:

停在中间自动翻页

序言:最近接到一个任务,做一个类似上面自动翻页的功能。可以看到,这一屏中有三张图片显示出来了,有两张没有显示完全,看到设计图的时候第一反应是可以用vIEwpager来实现,但是任务却跟你开了一个天大的玩笑,要求是以最左边的图片为基准,也就是说,左边的图片也得显示完全,就像下图所示,后来仔细想想vIEwpager好像没有这样的功能,也有可能是我不知道,我也没有找到这样的文章或者信息,希望知道的简友私戳交流一下,感激不尽,好了,言归正传

停在左边

在开始之前呢,首先介绍一个Google最新(其实在24.2.0版本的时候就已经发布了)发布的一个东西SnapHelper,这玩意儿是对RecyclerVIEw功能的一个拓展,有兴趣的同学可以去看看它的源码,SnapHelper的实现原理是监听RecyclerVIEw.OnFlingListener中的onFling接口,可以使RecyclerVIEw实现类似VIEwPager的功能,无论怎么滑动最终停留在某页正中间,那它和VIEwPager的区别是什么呢?就是VIEwPager不能一次连续滑动多张图片,而且不能定制(停在左边,还是停在右边)。下面我们一起来看看吧!

首先导入所需要的包,最低版本是v7-24.2.0,低了就没有这个类了:

compile 'com.androID.support:appcompat-v7:24.2.0'
compile 'com.androID.support:recyclervIEw-v7:24.2.0'

这里系统自带有一个类linearSnapHelper,linearSnapHelper继承自SnapHelper,这个默认是让视图停在中间的,你只需要将RecyclerVIEw和linearSnapHelper绑定在一起就行了:

linearSnapHelper mlinearSnapHelper = new linearSnapHelper();
mlinearSnapHelper.attachToRecyclerVIEw(mRecyclervIEw);

效果如下:

当然了,SnapHelper的功能绝不仅仅在此,你还可以定制化,让他停在左边,或者右边,而你不需要重新继承SnapHelper,直接继承linearSnapHelper就可以了,这里面有很多写好的方法,然后你再重写里面的两个方法:
* (1)、calculatedistancetoFinalSnap:当拖拽或滑动结束时会回调该方法,返回一个out = int[2],out[0]x轴,out[1] y轴 ,这个值就是需要修正的你需要的位置的偏移量。 *
* (2)、findSnapVIEw:这个方法用来获取特定的视图,当返回null时,表示没有获取到任何视图 。*

完整的代码:

public class leftSnapHelper extends linearSnapHelper { private OrIEntationHelper mHorizontalHelper; /** * 当拖拽或滑动结束时会回调该方法,该方法返回的是一个长度为2的数组,out[0]表示横轴,x[1]表示纵轴,这两个值就是你需要修正的位置的偏移量 * * @param layoutManager * @param targetVIEw * @return */ @OverrIDe public int[] calculatedistancetoFinalSnap(RecyclerVIEw.LayoutManager layoutManager,VIEw targetVIEw) { //注:由于是横向滚动,在这里我们只考虑横轴的值 int[] out = new int[2]; if (layoutManager.canScrollHorizontally()) {  out[0] = distancetoStart(targetVIEw,getHorizontalHelper(layoutManager)); } else {  out[0] = 0; } return out; } /** * 这个方法是计算偏移量 * * @param targetVIEw * @param helper * @return */ private int distancetoStart(VIEw targetVIEw,OrIEntationHelper helper) { return helper.getDecoratedStart(targetVIEw) - helper.getStartAfterpadding(); } @OverrIDe public VIEw findSnapVIEw(RecyclerVIEw.LayoutManager layoutManager) { return findStartVIEw(layoutManager,getHorizontalHelper(layoutManager)); } /** * 找到第一个显示的vIEw * @param layoutManager * @param helper * @return */ private VIEw findStartVIEw(RecyclerVIEw.LayoutManager layoutManager,OrIEntationHelper helper) { if (layoutManager instanceof linearlayoutmanager) {  int firstChild = ((linearlayoutmanager) layoutManager).findFirstVisibleItemposition();  int lastChild = ((linearlayoutmanager) layoutManager).findLastVisibleItemposition();  if (firstChild == RecyclerVIEw.NO_position) {  return null;  }  //这是为了解决当翻到最后一页的时候,最后一个Item不能完整显示的问题  if (lastChild == layoutManager.getItemCount() - 1) {  return layoutManager.findVIEwByposition(lastChild);  }  VIEw child = layoutManager.findVIEwByposition(firstChild);  //得到此时需要左对齐显示的条目  if (helper.getDecoratedEnd(child) >= helper.getDecoratedMeasurement(child) / 2   && helper.getDecoratedEnd(child) > 0) {  return child;  } else {  return layoutManager.findVIEwByposition(firstChild + 1);  } } return super.findSnapVIEw(layoutManager); } /** * 获取视图的方向 * * @param layoutManager * @return */ private OrIEntationHelper getHorizontalHelper(@NonNull RecyclerVIEw.LayoutManager layoutManager) { if (mHorizontalHelper == null) {  mHorizontalHelper = OrIEntationHelper.createHorizontalHelper(layoutManager); } return mHorizontalHelper; }}

当然了,你也可以让它停在右边:只需要在上面的基础上修改findSnapVIEw方法即可:

public class RightSnapHelper extends linearSnapHelper { private OrIEntationHelper mHorizontalHelper; /** * 当拖拽或滑动结束时会回调该方法,在这里我们只考虑横轴的值 int[] out = new int[2]; if (layoutManager.canScrollHorizontally()) {  out[0] = distancetoEnd(targetVIEw,getHorizontalHelper(layoutManager)); } else {  out[0] = 0; } return out; } /** * 这个方法是计算偏移量 * * @param targetVIEw * @param helper * @return */ private int distancetoEnd(VIEw targetVIEw,OrIEntationHelper helper) { return helper.getDecoratedEnd(targetVIEw) - helper.getEndAfterpadding(); } @OverrIDe public VIEw findSnapVIEw(RecyclerVIEw.LayoutManager layoutManager) { return findEndVIEw(layoutManager,getHorizontalHelper(layoutManager)); } /** * 找到第一个显示的vIEw * * @param layoutManager * @param helper * @return */ private VIEw findEndVIEw(RecyclerVIEw.LayoutManager layoutManager,OrIEntationHelper helper) { if (layoutManager instanceof linearlayoutmanager) {  int lastChild = ((linearlayoutmanager) layoutManager).findLastVisibleItemposition();  if (lastChild == RecyclerVIEw.NO_position) {  return null;  }  VIEw child = layoutManager.findVIEwByposition(lastChild);  //得到此时需要右对齐显示的条目  if (helper.getDecoratedStart(child) >= helper.getDecoratedMeasurement(child) / 2   && helper.getDecoratedStart(child) > 0) {  return child;  } else {  return layoutManager.findVIEwByposition(lastChild - 1);  } } return super.findSnapVIEw(layoutManager); } /** * 获取视图的方向 * * @param layoutManager * @return */ private OrIEntationHelper getHorizontalHelper(@NonNull RecyclerVIEw.LayoutManager layoutManager) { if (mHorizontalHelper == null) {  mHorizontalHelper = OrIEntationHelper.createHorizontalHelper(layoutManager); } return mHorizontalHelper; }}

效果:

停在右边

那如何让它能无限的滑动呢?

这个当然是要在Adapter里面“做手脚”了,让获取Item总数的方法返回Integer.MAX_VALUE就可以了:

@OverrIDepublic int getItemCount() { return Integer.MAX_VALUE;}

然后在onBindVIEwHolder中获取List中的值时相应的取余就好了:

@OverrIDepublic voID onBindVIEwHolder(RecyclerVIEwHolder holder,int position) { GlIDe.with(mContext).load(mList.get(position % mList.size())  .getimageUrl()).placeholder(R.mipmap.ic_launcher)  .into(holder.ivImage); holder.tvname.setText(mList.get(position % mList.size()).getname());}

好了,做到这里就完成了80%了,接下来我们要让它能够自动滚动,如何能自动滚动呢?这里可以参考一下VIEwPager中自动滚动的效果,这里LZ使用的是Timer来实现,Timer有一个每隔多长时间执行一次的功能,在这里正好:

private int cnt = 2; //表示当前最右边显示的item的positionprivate boolean isSlIDingByHand = false; //表示是否是手在滑动private boolean isSlIDingauto = true; //表示是否自动滑动timer.schedule(new TimerTask() { @OverrIDe public voID run() {  if (isSlIDingauto) {  myHandler.sendEmptyMessage(CHANGE_ITEM);  } } },1000,3000);

考虑到这里有两种滑动,一种是用户手动的滑动,另一种是我们的Timer来出发滑动,我们还得对RecyclerVIEw设置监听,来简单判断一下是用户触发的还是Timer触发的:

alRecyclervIEw.addOnScrollListener(new RecyclerVIEw.OnScrollListener() { @OverrIDe public voID onScrollStateChanged(RecyclerVIEw recyclerVIEw,int newState) {  linearlayoutmanager manager = (linearlayoutmanager) recyclerVIEw.getLayoutManager();  int firstVisibleItemposition = manager.findFirstVisibleItemposition();  switch (newState) {  case SCRolL_STATE_IDLE: //(静止没有滚动)   if (isSlIDingByHand) {   Message msg = myHandler.obtainMessage();   msg.arg1 = firstVisibleItemposition;   msg.what = CHANGE_ITEM;   myHandler.sendMessage(msg);   }   break;  case SCRolL_STATE_DRAGGING: //(正在被外部拖拽,一般为用户正在用手指滚动)   isSlIDingByHand = true;   isSlIDingauto = false;   break;  case SCRolL_STATE_SETTliNG: //(自动滚动)   if (isSlIDingByHand) {   isSlIDingauto = false;   } else {   isSlIDingauto = true;   }   break;  } } });

最后的处理结果当然是交给Handler来了:

private static class MyHandler extends Handler { //采用弱引用的方式,防止内存泄漏 WeakReference<Centeractivity> weakReference; public MyHandler(Centeractivity mActivity) { this.weakReference = new WeakReference<>(mActivity); } @OverrIDe public voID handleMessage(Message msg) { final Centeractivity mActivity = weakReference.get(); Log.d(TAG,"handleMessage: " + "handler is running"); if (mActivity.isSlIDingByHand) {  mActivity.cnt = msg.arg1;  mActivity.isSlIDingByHand = false;  mActivity.isSlIDingauto = true;  mActivity.cnt+=2;  //让RecyclerVIEw平滑的滚动  mActivity.alRecyclervIEw.smoothScrollToposition(++mActivity.cnt); } else {  mActivity.alRecyclervIEw.smoothScrollToposition(++mActivity.cnt); } }}

这样差不多就好了,但是还有一个问题不知道各位有没有关注到,滚动的时候并没有那么平滑,找了好久不知道是什么原因,希望知道的朋友底下评论告知一声。

参考文章:
OrientationHelper API
Android24.2.0支持库中的SnapHelper学习和使用

感谢以上资料的帮助。

源码我已上传至Github,想了解的朋友可以自行下载,当然,如果有更好的想法,也可以一起交流。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程小技巧。

总结

以上是内存溢出为你收集整理的Android如何使用RecyclerView打造首页轮播图全部内容,希望文章能够帮你解决Android如何使用RecyclerView打造首页轮播图所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/web/1147071.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-31
下一篇 2022-05-31

发表评论

登录后才能评论

评论列表(0条)

保存