RecyclerView代替ViewPager实现Banner无限循环

举报
yd_221104950 发表于 2020/12/03 23:41:22 2020/12/03
【摘要】 为什么选用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

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。