RecyclerView代替ViewPager实现Banner无限循环
【摘要】 为什么选用RecyclerView来实现图片轮播?
RecyclerView有优秀的缓存机制缓存相同ItemRecyclerView的Adapter可以针对不同Item的 ViewType来缓存不同的ItemRecyclerView已经自带的解决了与ViewPager, RecyclerView等滑动控件中的嵌套滑动冲突RecyclerView自带是否预加载(即懒加载...
为什么选用RecyclerView来实现图片轮播?
- RecyclerView有优秀的缓存机制缓存相同Item
- RecyclerView的Adapter可以针对不同Item的 ViewType来缓存不同的Item
- RecyclerView已经自带的解决了与ViewPager, RecyclerView等滑动控件中的嵌套滑动冲突
- RecyclerView自带是否预加载(即懒加载)功能,可以垂直方向,水平方向滑动,如各种很炫的效果
不选用ViewPager来实现图片轮播的理由?
- 如果Banner嵌套在RecyclerView或ListView中, 那么ViewPager方式可能会出现动画卡顿和白屏,而RecyclerView则不会。
实例:
首先我们先自定义一个图片的指示:
在attrs.xml定义属性:
<?xml version="1.0" encoding="utf-8"?>
<resources> <declare-styleable name="PixIndicator"> <!-- 圆点的颜色 --> <attr name="selectColor" format="color" /> <!-- 未选中圆点的颜色 --> <attr name="unselectedColor" format="color" /> <!-- 圆点的大小 --> <attr name="radius" format="dimension" /> <!-- 圆点间间距的大小 --> <attr name="space" format="dimension" /> </declare-styleable>
</resources>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
定义图片指示器类:
package com.jk.displaypix;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;
import androidx.annotation.Nullable;
public class PixIndicator extends View { private int number; private int position = 0; private Paint paint = new Paint(); private int selectColor; private int unselectColor; private float radius; private float space; // 最新被执行 { paint.setStyle(Paint.Style.FILL); paint.setAntiAlias(true); } public PixIndicator(Context context) { this(context,null); } public PixIndicator(Context context, @Nullable AttributeSet attrs) { super(context, attrs); // 获取在布局文件中配置的属性值 TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.PixIndicator); this.selectColor = typedArray.getColor(R.styleable.PixIndicator_selectColor, Color.RED); this.unselectColor = typedArray.getColor(R.styleable.PixIndicator_unselectedColor, Color.BLACK); this.radius = typedArray.getDimension(R.styleable.PixIndicator_radius, 10); this.space = typedArray.getDimension(R.styleable.PixIndicator_space, 20); typedArray.recycle(); } // 图出所有点 @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.save(); float startPosition = ((float)getWidth()) / 2 - (radius * 2 * number + space * (number - 1)) / 2; for (int i = 0; i < number; i++) { if (i == position) { paint.setColor(selectColor); } else { paint.setColor(unselectColor); } canvas.drawCircle(startPosition + radius * (2 * i + 1) + i * space, ((float)getHeight()) / 2, radius, paint); } canvas.restore(); } // 设置图片数量 public void setSize(int number) { this.number = number; } // 设置当前图片位置 public void setCurrentPosition(int position) { this.position = position; invalidate(); }
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
第一步设置好布局:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <androidx.recyclerview.widget.RecyclerView android:id="@+id/recycler" android:layout_width="match_parent" android:layout_height="200dp" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintEnd_toEndOf="parent" /> <com.jk.displaypix.PixIndicator android:id="@+id/indicator" android:layout_width="wrap_content" android:layout_height="32dp" app:selectColor="@color/colorAccent" app:unselectedColor="#ffffff" app:radius="3dp" app:space="10dp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintBottom_toBottomOf="@id/recycler"/>
</androidx.constraintlayout.widget.ConstraintLayout>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
第二步准备好图片:
List<Integer> list = new ArrayList<>(4);
// 存入图片
list.add(R.drawable.b1);
list.add(R.drawable.b2);
list.add(R.drawable.b3);
list.add(R.drawable.b4);
- 1
- 2
- 3
- 4
- 5
- 6
第三步准备好RecyclerView Adapter:
package com.jk.displaypix;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.Glide;
import java.util.List;
public class BannerAdapter extends RecyclerView.Adapter<BannerAdapter.ViewHolder> { private List<Integer> list; private Context context; public BannerAdapter(Context context, List<Integer> list){ this.list=list; this.context=context; } @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view= LayoutInflater.from(parent.getContext()).inflate(R.layout.item_image,parent,false); return new ViewHolder(view); } @Override public void onBindViewHolder(ViewHolder holder, int position) { Glide.with(context).load(list.get(position%list.size())).into(holder.imageView); } @Override public int getItemCount() { return Integer.MAX_VALUE; } class ViewHolder extends RecyclerView.ViewHolder { private ImageView imageView; public ViewHolder(View itemView) { super(itemView); imageView= itemView.findViewById(R.id.item_image); } }
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
第四步:配置RecyclerView
BannerAdapter adapter = new BannerAdapter(this, list); RecyclerView recyclerView = findViewById(R.id.recycler); // LinearLayoutManager 第二个参数表示布局方向,默认是垂直的 // 这里轮播广告要用为LinearLayoutManager.HORIZONTAL,水平方向 // 使用LinearLayoutManager会让图片滚动太快,我们继承LinearLayoutManager写一个子类重写它的滑动,让它不要太快 // LinearLayoutManager layoutManager = new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false); SmoothLinearLayoutManager layoutManager = new SmoothLinearLayoutManager(this, SmoothLinearLayoutManager.HORIZONTAL, false); recyclerView.setLayoutManager(layoutManager); recyclerView.setHasFixedSize(true); recyclerView.setAdapter(adapter); // 由于广告是一页一页的划过去,所以我们还需要用SnapHelper的子类PagerSnapHelper。直接追加到上面的recyclerView.setAdapter(adapter) 后面。 PagerSnapHelper snapHelper = new PagerSnapHelper(); snapHelper.attachToRecyclerView(recyclerView); // recyclerView.scrollToPosition(list.size()*10)这句使RecyclerView一开始位于 list.size()*10 处,避免了一开始position为0不能前滑的尴尬 recyclerView.scrollToPosition(list.size() * 10);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
第五步:实现自动播放
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1); scheduledExecutorService.scheduleAtFixedRate(new Runnable() { @Override public void run() { // layoutManager.findFirstVisibleItemPosition() 表示得到当前RecyclerView第一个能看到的item的位置。 // 由于广告是每次展示一张,所以得到的就是当前图片的position。 // recyclerView.smoothScrollToPosition(int position)表示滑动到某个position。 // 所以上面的代码就表示每过2秒滑动到下个position,以此来完成自动轮播。 recyclerView.smoothScrollToPosition(layoutManager.findFirstVisibleItemPosition() + 1); } }, 2000, 2000, TimeUnit.MILLISECONDS);// 表示2秒后每过2秒运行一次run()里的程序
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
第六步:更新图片指示器
final PixIndicator bannerIndicator = findViewById(R.id.indicator); bannerIndicator.setSize(list.size()); recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) { // onScrollStateChangedd的 newState 参数有三种状态: // SCROLL_STATE_IDLE 静止状态 // SCROLL_STATE_DRAGGING 拖拽状态 // SCROLL_STATE_SETTLING手指离开后的惯性滚动状态 // 当RecyclerView的状态为SCROLL_STATE_IDLE时得到当前图片的position,然后与图片列表取余就得到指示器红点的位置。 if (newState == RecyclerView.SCROLL_STATE_IDLE) { int i = layoutManager.findFirstVisibleItemPosition() % list.size(); //得到指示器红点的位置 bannerIndicator.setCurrentPosition(i); } } });
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
轮播图的Demo共享在GitHub了
谢谢阅读
文章来源: blog.csdn.net,作者:WongKyunban,版权归原作者所有,如需转载,请联系作者。
原文链接:blog.csdn.net/weixin_40763897/article/details/99845377
【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)