Android 使用RecyclerView实现轮播图
一、需求
之前一篇博客使用ViewPager实现轮播图《Android ViewPager实现循环轮播图》,但是ViewPager有个天生的缺陷是View无法重用,此外ViewPager的滑动过程会频繁requestLayout,尽管可以通过addViewInLayout和removeViewInLayout配合PagerAdapter 的startUpdate和finishUpdate可以减少重绘,但在ListView和RecyclerView中仍然达不到最好的效果。因此,使用一种新的方式十分必要。
二、代码实现
RecyclerPagerView
public class RecyclerPagerView extends RecyclerView implements Handler.Callback { private static final long TASK_TIMEOUT = 3000; public OnPageChangeListener onPageChangeListener; private final Handler mRecyclerHandler; private final int MSG_PLAY_NEXT = 112233; private volatile boolean isPlaying = false; private boolean lastIsPlayState = false; private int realPosition = -1; public RecyclerPagerView(Context context) { this(context,null); } public RecyclerPagerView(Context context, @Nullable AttributeSet attrs) { this(context, attrs,0); } public RecyclerPagerView(Context context, @Nullable AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); mRecyclerHandler = new Handler(Looper.getMainLooper(),this); } public void setOnPageChangeListener(OnPageChangeListener onPageChangeListener) { this.onPageChangeListener = onPageChangeListener; if(this.onPageChangeListener!=null){ addOnScrollListener(this.onPageChangeListener); int currentItem = getCurrentItem(); this.onPageChangeListener.onPageSelection(currentItem); } } public int getCurrentItem(){ LinearLayoutManager linearLayoutManager = (LinearLayoutManager) getLayoutManager(); return linearLayoutManager.findFirstVisibleItemPosition(); } public void setCurrentItem(int position,boolean isAnimate){ Adapter adapter = getAdapter(); if(adapter==null || adapter.getItemCount()<=position){ return; } if(!isAnimate) { scrollToPosition(position); }else { smoothScrollToPosition(position); } } public void setCurrentItem(int position ){ setCurrentItem(position,true); } @Override public boolean fling(int velocityX, int velocityY) { LinearLayoutManager linearLayoutManager = (LinearLayoutManager) getLayoutManager(); int screenWidth = Resources.getSystem().getDisplayMetrics().widthPixels; // views on the screen int lastVisibleItemPosition = linearLayoutManager.findLastVisibleItemPosition(); View lastView = linearLayoutManager.findViewByPosition(lastVisibleItemPosition); int firstVisibleItemPosition = linearLayoutManager.findFirstVisibleItemPosition(); View firstView = linearLayoutManager.findViewByPosition(firstVisibleItemPosition); // distance we need to scroll int leftMargin = (screenWidth - lastView.getWidth()) / 2; int rightMargin = (screenWidth - firstView.getWidth()) / 2 + firstView.getWidth(); int leftEdge = lastView.getLeft(); int rightEdge = firstView.getRight(); int scrollDistanceLeft = leftEdge - leftMargin; int scrollDistanceRight = rightMargin - rightEdge; int targetPosition; if (Math.abs(velocityX) < 1500) { // The fling is slow -> stay at the current page if we are less than half through, // or go to the next page if more than half through if (leftEdge > screenWidth / 2) { // go to next page smoothScrollBy(-scrollDistanceRight, 0); targetPosition = firstVisibleItemPosition; } else if (rightEdge < screenWidth / 2) { // go to next page smoothScrollBy(scrollDistanceLeft, 0); targetPosition = firstVisibleItemPosition+1; } else { // stay at current page if (velocityX > 0) { smoothScrollBy(-scrollDistanceRight, 0); } else { smoothScrollBy(scrollDistanceLeft, 0); } targetPosition = firstVisibleItemPosition; } } else { // The fling is fast -> go to next page if (velocityX > 0) { smoothScrollBy(scrollDistanceLeft, 0); targetPosition = firstVisibleItemPosition+1; } else { smoothScrollBy(-scrollDistanceRight, 0); targetPosition = firstVisibleItemPosition; } } Log.e("RecyclerPagerView","nextPage="+targetPosition); if(this.onPageChangeListener!=null){ realPosition = targetPosition; this.onPageChangeListener.onPageSelection(targetPosition); } return true; } @Override public void onScrollStateChanged(final int state) { super.onScrollStateChanged(state); if (state == SCROLL_STATE_IDLE) { LinearLayoutManager linearLayoutManager = (LinearLayoutManager) getLayoutManager(); int screenWidth = Resources.getSystem().getDisplayMetrics().widthPixels; int lastVisibleItemPosition = linearLayoutManager.findLastVisibleItemPosition(); View lastView = linearLayoutManager.findViewByPosition(lastVisibleItemPosition); int firstVisibleItemPosition = linearLayoutManager.findFirstVisibleItemPosition(); View firstView = linearLayoutManager.findViewByPosition(firstVisibleItemPosition); // distance we need to scroll int leftMargin = (screenWidth - lastView.getWidth()) / 2; int rightMargin = (screenWidth - firstView.getWidth()) / 2 + firstView.getWidth(); int leftEdge = lastView.getLeft(); int rightEdge = firstView.getRight(); int scrollDistanceLeft = leftEdge - leftMargin; int scrollDistanceRight = rightMargin - rightEdge; int targetPosition = -1; if (leftEdge > screenWidth / 2) { smoothScrollBy(-scrollDistanceRight, 0); targetPosition = firstVisibleItemPosition+1; } else if (rightEdge < screenWidth / 2) { smoothScrollBy(scrollDistanceLeft, 0); targetPosition = lastVisibleItemPosition; }else{ targetPosition = firstVisibleItemPosition; } if(this.onPageChangeListener!=null){ realPosition = targetPosition; this.onPageChangeListener.onPageSelection(targetPosition); } } } @Override public boolean handleMessage(Message msg) { int what = msg.what; switch (what){ case MSG_PLAY_NEXT: showNextPage(); break; } return false; } private void showNextPage() { if(!isPlaying){ return; } if(!canRecyclePlaying()){ isPlaying = false; return; } Adapter adapter = getAdapter(); int currentItem = getCurrentItem(); if(adapter!=null && adapter.getItemCount()>0) { if (currentItem == NO_POSITION ) { setCurrentItem(0); }else { setCurrentItem(currentItem+1); } } mRecyclerHandler.sendEmptyMessageDelayed(MSG_PLAY_NEXT,TASK_TIMEOUT); } public void startPlay(){ if(isPlaying){ stopPlay(); } if (!canRecyclePlaying()){ isPlaying = false; return; } isPlaying = true; mRecyclerHandler.sendEmptyMessageDelayed(MSG_PLAY_NEXT,TASK_TIMEOUT); } @Override public void setAdapter(Adapter adapter) { super.setAdapter(adapter); if(canRecyclePlaying()){ if(realPosition==-1){ realPosition = 1000; } setCurrentItem(realPosition,false); } } private boolean canRecyclePlaying() { Adapter adapter = getAdapter(); if(adapter==null || adapter.getItemCount()<1) return false; return true; } private void stopPlay() { isPlaying = false; mRecyclerHandler.removeMessages(MSG_PLAY_NEXT); } @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); if(lastIsPlayState){ startPlay(); } } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); lastIsPlayState = isPlaying; stopPlay(); } public static abstract class OnPageChangeListener extends RecyclerView.OnScrollListener{ public abstract void onPageSelection(int position); } }
Adapter+Holder 适配器
该类的作用主要用于约束和快速接入
public class QuickViewHolder extends RecyclerView.ViewHolder{ private SparseArray<View> mViews; private View mConvertView; private QuickViewHolder(View v){ super(v); mConvertView = v; mViews = new SparseArray<>(); } public static QuickViewHolder get(ViewGroup parent, int layoutId){ View convertView = LayoutInflater.from(parent.getContext()).inflate(layoutId, parent, false); return new QuickViewHolder(convertView); } public <T extends View> T getView(int id){ View v = mViews.get(id); if(v == null){ v = mConvertView.findViewById(id); mViews.put(id, v); } return (T)v; } }
BannerAdapter实现,该类继承QuickAdapter
public class BannerAdapter extends QuickAdapter<String> { public BannerAdapter(List<String> datas) { super(datas); } @Override public int getLayoutId(int viewType) { return R.layout.item_banner_image; } @Override public void convert(QuickViewHolder holder, String url, int position) { final Resources resources = holder.itemView.getResources(); final int drawableId = resources.getIdentifier(url, "drawable", holder.itemView.getContext().getPackageName()); if(drawableId!=0) { ImageView bannerImage = holder.getView(R.id.banner_image_item); bannerImage.setImageResource(drawableId); } } }
三、使用
final RecyclerPagerView rpv = findViewById(R.id.recycler_pager); tipTextView = findViewById(R.id.tip_text); LinearLayoutManager lm = new LinearLayoutManager(this,LinearLayoutManager.HORIZONTAL,false); rpv.setLayoutManager(lm); List<String> imagelist = new ArrayList<>(); imagelist.add("banner_t1"); imagelist.add("banner_t2"); imagelist.add("banner_t3"); imagelist.add("banner_t4"); rpv.setAdapter(new BannerAdapter(imagelist)); rpv.setOnPageChangeListener(new PagerChangeListener(tipTextView,imagelist.size())); rpv.startPlay();
监听器
public static class PagerChangeListener extends RecyclerPagerView.OnPageChangeListener { private TextView tipTextView; private int size; public PagerChangeListener(TextView tipTextView,int size) { this.tipTextView = tipTextView; this.size = size; } @Override public void onPageSelection(int position) { tipTextView.setText((position%size+1)+"/"+size); } }

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
解决Redis集群条件下键空间通知服务器接收不到消息的问题
解决Redis集群条件下键空间通知服务器接收不到消息的问题 键空间通知介绍 键空间通知使得客户端可以通过订阅频道或模式, 来接收那些以某种方式改动了 Redis 数据集的事件。 可以通过对redis的redis.conf文件中配置notify-keyspace-events参数可以指定服务器发送哪种类型的通知。下面对于一些参数的描述。默认情况下此功能是关闭的。 字符 通知 K 键空间通知,所有通知以 __keyspace@<db>__ 为前缀 E 键事件通知,所有通知以 __keyevent@<db>__ 为前缀 g DEL 、 EXPIRE 、 RENAME 等类型无关的通用命令的通知 $ 字符串命令的通知 l 列表命令的通知 s 集合命令的通知 h 哈希命令的通知 z 有序集合命令的通知 x 过期事件:每当有过期键被删除时发送 e 驱逐(evict)事件:每当有键因为 maxmemory 政策而被删除时发送 A 参数 g$lshzxe 的别名 所以当你配置文件中配置为AKE时就表示发送所有类型的通知。 在程序中接入 使用SpringData可以轻松的实现对于...
- 下一篇
docker CE on Linux示例浅析(二)数据存储与持久化
概述 github项目地址:https://github.com/superwujc 尊重原创,欢迎转载,注明出处:https://my.oschina.net/superwjc/blog/3043665 历史系列: docker CE on Linux示例浅析(一)安装与基本运行 docker对容器采用分层式(layer)管理,运行中的容器包括若干位于底部的镜像层与一个位于顶部的容器层。镜像层在构建完成时确定,属性为只读,内容始终保持不变;容器层在容器启动时添加,属性为读写,内容随运行而变化。默认情况下,容器中发生的所有文件变更仅影响当前容器自身的可写层,且可写层中的数据会随容器的移除而永久丢失。 docker提供了以下3种方式,将宿主机上的文件/目录挂载到容器,而容器则将需要保留的数据写入到挂载点而非可写层,以实现容器数据的持久化与共享功能: 数据卷(data volume) 绑定挂载(bind mount) Linux特有的临时文件系统(tmpfs) 这3种挂载类型都在容器启动时指定,对应的命令为docker run。在早期的docker版本中,数据卷与绑定挂载由-v/--...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- CentOS8安装MyCat,轻松搞定数据库的读写分离、垂直分库、水平分库
- Red5直播服务器,属于Java语言的直播服务器
- Eclipse初始化配置,告别卡顿、闪退、编译时间过长
- SpringBoot2全家桶,快速入门学习开发网站教程
- CentOS7设置SWAP分区,小内存服务器的救世主
- CentOS7安装Docker,走上虚拟化容器引擎之路
- CentOS7编译安装Cmake3.16.3,解决mysql等软件编译问题
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- CentOS8安装Docker,最新的服务器搭配容器使用
- SpringBoot2初体验,简单认识spring boot2并且搭建基础工程