你的浏览器禁用了JavaScript, 请开启后刷新浏览器获得更好的体验!
首页
热门
推荐
精选
登录
|
注册
利用RecyclerView实现无限轮播广告条
立即下载
用AI写一个
金额:
2
元
支付方式:
友情提醒:源码购买后不支持退换货
立即支付
我要免费下载
发布时间:2018-12-31
5人
|
浏览:2463次
|
收藏
|
分享
技术:Android+Java
运行环境:AndroidStudio+Android手机
概述
利用RecyclerView实现一款广告轮播悬浮条
详细
> 前言: 公司产品需要新增悬浮广告条的功能,要求是可以循环滚动,并且点击相应的浮条会跳转到相应的界面,在实现这个功能的时候遇到一些坑,幸运的是最后从这些坑中爬了出来。这篇文章的主要内容就是介绍功能的实现以及爬坑的经验。 ### 效果展示 在文章开始前,先看下最后实现的效果,最终的效果如下图 ![](https://user-gold-cdn.xitu.io/2018/12/30/167fd7cfa6085c73?w=320&h=609&f=gif&s=409263) ### 需求分析 我们已经知道了产品的需求,下面要做的就是分析这个需求应该怎样实现,首先我们要实现的功能就是让广告条循环滚动,看最终的效果图可以发现,滚动的方向是由下往上滚动,平时我们见的banner图都是左右滚动的,如果是左右滚动的就好办了,可以通过`ViewPager`来实现。但是这个上下滚动的应该怎么实现呢?首先,想到的是利用`ViewFlipper`这个系统控件,但是这个控件只能满足循环滚动这个功能,我们还有一个需求是点击不同的浮条跳转不同的内容呢!这个功能`ViewFlipper`就无法满足了。既要循环滚动又要每个浮条有相应的点击事件,自然的就想到了`RecyclerView`,下面就利用RecyclerView来实现这些需求。 ### 功能实现 RecyclerView的使用相信大家都会的,但是这里有个问题是怎样让RecyclerView循环滚动?再把问题细分一下,首先就是怎样让RecyclerView自己滚动,然后是怎样实现里面的内容循环。 #### 动起来吧!RecyclerView 怎样让RecyclerView自己滚动呢?通过查官方的Api,发现RecyclerView的LayoutManager中有这样一个方法 ![](https://user-gold-cdn.xitu.io/2018/12/30/167fd97c66ee20b4?w=865&h=626&f=png&s=131927) 这个方法的说明是 > 使用提供的SmoothScroller开始平滑滚动。 好了,现在我们知道了这个方法的作用是让RecyclerView平滑滚动的,既然是让RecyclerView平滑滚动,那么我们肯定要告诉`startSmoothScroll`方法,RecyclerView怎样滚动,如,滚动的方向、距离、速度等。上面的方法说明也说了根据提供的`SmoothScroller`滚动,因此这里我们要实现`SmoothScroller`类来制定一些滚动的规则,查看源码可以发现`SmoothScroller`是抽象类,而官方文档中说它的已知的直接实现类是[LinearSmoothScroller](https://developer.android.google.cn/reference/android/support/v7/widget/LinearSmoothScroller.html),所以这里直接实例化`LinearSmoothScroller`,重写相应的方法即可。具体代码如下 ```java mSmoothScroller = new LinearSmoothScroller(this) { @Override protected int getVerticalSnapPreference() { return LinearSmoothScroller.SNAP_TO_START; } @Override protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) { return 3f / (displayMetrics.density); } }; ``` 可以看到这里重写了两个方法。`getVerticalSnapPreference`这个方法是制定对齐的规则,就是RecyclerView里面的item顶部或底部与RecyclerView的对齐方式,这里有三种对齐方式,以下是官方文档中对这三种对齐方式的具体说明 ![](https://user-gold-cdn.xitu.io/2018/12/30/167fdb5910641e99?w=855&h=283&f=png&s=35001) 再看下`calculateSpeedPerPixel`这个方法,这个方法是用来计算滚动的速度的,返回值是滚动一个像素花费的毫秒数。`displayMetrics.density`这个是1dp对应的像素密度,就是1dp等于多少像素。
注:`SmoothScroller`是将目标item滚动到RecyclerView中,即让目标item在RecyclerView中可见。
已经设置好滚动的规则了,下面要做的就是让RecyclerView中的item滚动,并且循环滚动。 #### 实现RecyclerView的循环滚动 在实现循环滚动之前,看下实现滚动的代码,如下 ```java private void startAuto() { if (mAutoTask != null && !mAutoTask.isDisposed()) { mAutoTask.dispose(); } mAutoTask = Observable.interval(1, 2, TimeUnit.SECONDS).observeOn(AndroidSchedulers.mainThread()).subscribe(new Consumer
() { @Override public void accept(Long aLong) { mSmoothScroller.setTargetPosition(aLong.intValue()); RecyclerView.LayoutManager layoutManager = mRecyclerView.getLayoutManager(); if (layoutManager!=null) layoutManager.startSmoothScroll(mSmoothScroller); } }); } ``` 从这段代码中可以看到,用RxJava中的`interval`方法实现了一个循环数字递增定时器,时间间隔是2s。`mSmoothScroller.setTargetPosition(aLong.intValue());`这句代码就是设置哪个item出现在RecyclerView中。`layoutManager.startSmoothScroll(mSmoothScroller);`这句代码实际上调用的就是`LinearSmoothScroller`类中的`start`方法,这段代码实现的功能就是每隔两秒,就让设置的目标item平滑滚动到RecyclerView中。 现在已经开始滚动了,那么怎么让目标item重复出现呢?其实这很简单,就是将itemCount设置成无限大,具体代码如下 ```java @Override public int getItemCount() { return Integer.MAX_VALUE; } @Override public void onBindViewHolder(@NonNull final AdViewHolder holder, int position) { if (mDynamicAdsDetails.size() != 0) { String media1 = mDynamicAdsDetails.get(position % mDynamicAdsDetails.size()); Picasso.get() .load(media1) .error(R.mipmap.ic_launcher) .placeholder(R.mipmap.ic_launcher) .into( holder.ivFlipperItem); } holder.itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //控制点击频率 if ((System.currentTimeMillis() - between) / 1000 < 1) { return; } between = System.currentTimeMillis(); Toast.makeText(mContext,"点击了第"+holder.getAdapterPosition() % mDynamicAdsDetails.size()+"个",Toast.LENGTH_SHORT).show(); } }); } ```
注:将itemCount设置成无限大后,取列表中的值时,不能直接根据相应的`position`来取值了,应该这样取`mDynamicAdsDetails.get(position % mDynamicAdsDetails.size())`。
这样就能实现循环滚动了。 ### 开始爬坑 #### 图片错乱问题 这样实现看起来显然没问题,但是项目跑起来后,却发现图片竟然不是循环显示的,而是偶尔会一张图片出现多次,然后才是下一张图片。分析了一下原因,认为是RecyclerView的复用问题,图片异步请求的结果还没有返回回来,复用了上次的控件,所以就出现一个图片显示多次的问题了。解决方法就是给ImageView设置Tag,具体代码如下 ```java if (mDynamicAdsDetails.size() != 0) { String media1 = mDynamicAdsDetails.get(position % mDynamicAdsDetails.size()); holder.ivFlipperItem.setTag(media1); Picasso.get() .load(media1) .error(R.mipmap.ic_launcher) .placeholder(R.mipmap.ic_launcher) .into(new com.squareup.picasso.Target() { @Override public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) { if (mDynamicAdsDetails.get(holder.getAdapterPosition() % mDynamicAdsDetails.size()).equals(holder.ivFlipperItem.getTag())) { holder.ivFlipperItem.setScaleType(ImageView.ScaleType.FIT_XY); holder.ivFlipperItem.setImageBitmap(bitmap); } } @Override public void onBitmapFailed(Exception e, Drawable errorDrawable) { } @Override public void onPrepareLoad(Drawable placeHolderDrawable) { } }); } ``` #### 滚动问题 先看下滑动RecyclerView时出现的问题,如图 ![](https://user-gold-cdn.xitu.io/2018/12/30/167fe1b24d3dcea1?w=320&h=604&f=gif&s=2004512) 可以发现,虽然可以滑动RecyclerView,但是滑动过后,item会回退回来,然后继续上次的位置开始滚动。这个问题解决方法有两种 1. 记住手动滑动到的item的未知,然后在`interval`方法中把滑动的位置设置为目标位置。 2. 禁止RecyclerView的滑动。 因为需求没有可以滑动的这个功能,所以这里采用方法2,禁止RecyclerView的滑动,详细代码如下 ```java public class AutoScrollRecyclerView extends RecyclerView { private int mState; private OnScrollListener mScrollListener; public AutoScrollRecyclerView(Context context) { this(context,null); } public AutoScrollRecyclerView(Context context, @Nullable AttributeSet attrs) { this(context, attrs,0); } public AutoScrollRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } @Override public boolean onTouchEvent(MotionEvent e) { switch (e.getAction()) { case MotionEvent.ACTION_DOWN: case MotionEvent.ACTION_UP: return true; case MotionEvent.ACTION_MOVE: return false; case MotionEvent.ACTION_POINTER_UP: return false; } return true; } } ``` 这里重写了RecyclerVieiew的`onTouchEvent`方法,当滑动式返回`false`,不消费滑动的动作。 但是,这么做之后会有新的问题,就是当图片在滚动时,我们点击图片,图片会暂停住,这里采用的解决方法是监听RecyclerView 的滚动状态,只有当RecyclerView滑动停止时,才不拦截事件,否则就拦截事件。具体代码如下 ```java public class AutoScrollRecyclerView extends RecyclerView { private int mState; private OnScrollListener mScrollListener; public AutoScrollRecyclerView(Context context) { this(context,null); } public AutoScrollRecyclerView(Context context, @Nullable AttributeSet attrs) { this(context, attrs,0); } public AutoScrollRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); mScrollListener = new OnScrollListener() { @Override public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); mState = newState; } }; //添加RecyclerView的滑动监听 addOnScrollListener(mScrollListener); } //判断是否拦截事件 @Override public boolean onInterceptTouchEvent(MotionEvent e) { return mState != 0; } @Override public boolean onTouchEvent(MotionEvent e) { switch (e.getAction()) { case MotionEvent.ACTION_DOWN: case MotionEvent.ACTION_UP: return mState == 0; case MotionEvent.ACTION_MOVE: return false; case MotionEvent.ACTION_POINTER_UP: return false; } return true; } } ``` 好了,这样就解决了滑动RecyclerView出现的问题。 ### 自定义广告样式 广告的样式是可以自己定义的,不仅仅是图片,还可以实现图文混排等,只需要修改layout文件即可,这里为了方便就直接在layout中放了一张图片。 ### 项目结构 文章中的项目结构如下图所示 ![](https://user-gold-cdn.xitu.io/2018/12/30/167fe6f24990ffc7?w=424&h=695&f=png&s=85877) ### 结束语 实现的功能挺简单的,但是如果对RecyclerView滑动的方法不熟悉的话,实现起来还是有点难度的,还有就是我们在编写代码的时候不仅要实现功能,还有注意对一些细节的处理,如果细节处理的不好,是很影响用户体验的。一些细节方面的问题是很考验技能的,当然对技能提升的帮助也是很大的。
本实例支付的费用只是购买源码的费用,如有疑问欢迎在文末留言交流,如需作者在线代码指导、定制等,在作者开启付费服务后,可以点击“购买服务”进行实时联系,请知悉,谢谢
感谢
0
手机上随时阅读、收藏该文章 ?请扫下方二维码
相似例子推荐
评论
作者
wizardev
6
例子数量
273
帮助
29
感谢
评分详细
可运行:
4.5
分
代码质量:
4.5
分
文章描述详细:
4.5
分
代码注释:
4.5
分
综合:
4.5
分
作者例子
Android蓝牙
Android低功耗蓝牙(BLE)使用详解
手撸一款精美的水波气泡
利用RecyclerView实现无限轮播广告条
一款“灵动”的滑动按钮
搞懂Nfc刷卡看这篇就够了