欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

RecyclerView实现广告轮播图

程序员文章站 2022-05-14 19:37:15
...

平时都是用RecyclerView实现列表,RecyclerView的强大毋庸置疑,今天就用它来实现广告轮播图。 
   
  效果如下 
RecyclerView实现广告轮播图

  首先,在activity_main.xml里定义布局 
  

<RelativeLayout
    ...
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/recycler"
        android:layout_width="match_parent"
        android:layout_height="144dp">

    </android.support.v7.widget.RecyclerView>

</RelativeLayout>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

  然后定义列表的item布局—-item_image.xml:

<LinearLayout
    ...
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <ImageView
        android:id="@+id/item_image"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scaleType="centerCrop"/>

</LinearLayout>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

  然后是Adapter,在Adapter初始化时要传入图片列表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= (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

   
  上面代码里需要注意的地方有两处。 
   
  第一处是getItemCount() 返回的是Integer.MAX_VALUE。这是因为广告轮播图是无限轮播,getItemCount() 返回的是Adapter中的总项目数,这样才能使RecyclerView能一直滚动。 
   
  第二处是onBindViewHolder()中的 position%list.size() ,表示position对图片列表list取余,这样list.get(position%list.size())才能按顺序循环展示图片。

   
  MainActivity.java代码如下:

public class MainActivity extends AppCompatActivity {
    private List<Integer> list = new ArrayList<>(4);

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //存入图片
        list.add(R.drawable.b1);
        list.add(R.drawable.b2);
        list.add(R.drawable.b3);
        list.add(R.drawable.b4);


        BannerAdapter adapter = new BannerAdapter(this, list);
        RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler);
        LinearLayoutManager layoutManager = new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false);
        recyclerView.setLayoutManager(layoutManager);
        recyclerView.setHasFixedSize(true);
        recyclerView.setAdapter(adapter);
        recyclerView.scrollToPosition(list.size()*10);

    }
}
  • 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

   需要注意的是LinearLayoutManager 第二个参数表示布局方向,平时默认是垂直的,也就是我们常见的列表样式。这里轮播广告要用为LinearLayoutManager.HORIZONTAL,水平方向。 
   还有一点需要注意,recyclerView.scrollToPosition(list.size()*10)这句使RecyclerView一开始位于 list.size()*10 处,避免了一开始position为0不能前滑的尴尬。 
   
  由于广告是一页一页的划过去,所以我们还需要用到一个类,SnapHelper的子类PagerSnapHelper,用起来很简单,两句话。直接追加到上面的recyclerView.setAdapter(adapter) 后面。

public class MainActivity extends AppCompatActivity {
    ...

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        ...
        recyclerView.setAdapter(adapter);

        PagerSnapHelper snapHelper = new PagerSnapHelper();
        snapHelper.attachToRecyclerView(recyclerView);

    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

  然后加入自动轮播,此处使用ScheduledExecutorService 来完成。

        ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);
        scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                recyclerView.smoothScrollToPosition(layoutManager.findFirstVisibleItemPosition() + 1);
            }
        }, 2000, 2000, TimeUnit.MILLISECONDS);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

这段代码表示2秒后每过2秒运行一次run()里的程序 。layoutManager.findFirstVisibleItemPosition() 表示得到当前RecyclerView第一个能看到的item的位置。由于广告是每次展示一张,所以得到的就是当前图片的position。recyclerView.smoothScrollToPosition(int position)表示滑动到某个position。所以上面的代码就表示每过2秒滑动到下个position,以此来完成自动轮播。

  还有一点还要改进,程序运行起来后会发现自动轮播切换图片时速度太快了,这个怎么解决呢? 
  点开LinearLayoutManager的源码,查找smoothScrollToPosition()方法。 
  RecyclerView实现广告轮播图 
这里滑动用到了LinearSmoothScroller,继续点击去,里面有一个calculateSpeedPerPixel()方法。 
RecyclerView实现广告轮播图
  官方注释:计算滚动速度。如果返回值是2毫秒,这表示着滚动1000像素需要2秒。 
所以我们继承LinearLayoutManager,重写smoothScrollToPosition()方法,并将里面的修改LinearSmoothScroller的这个方法返回值修改。

  新建SmoothLinearLayoutManager.java 文件,代码如下: 
  

public class SmoothLinearLayoutManager extends LinearLayoutManager {

    public SmoothLinearLayoutManager(Context context) {
        super(context);
    }

    public SmoothLinearLayoutManager(Context context, int orientation, boolean reverseLayout) {
        super(context, orientation, reverseLayout);
    }

    @Override
    public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position) {
        LinearSmoothScroller linearSmoothScroller =
                new LinearSmoothScroller(recyclerView.getContext()) {
                    protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) {
                        return 0.2f; //返回0.2
                    }
                };
        linearSmoothScroller.setTargetPosition(position);
        startSmoothScroll(linearSmoothScroller);
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

  
   
  程序写到这里,广告轮播图已初具雏形了,最后还差个指示器。 
   
  显示指示器上的红点需要得到当前展示的广告轮播图片的position。RecyclerView有个addOnScrollListener()方法,可以监听当前滑动状态。所以代码如下: 
  

        recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                if (newState == RecyclerView.SCROLL_STATE_IDLE) {
                    int i = layoutManager.findFirstVisibleItemPosition() % list.size();
                    //得到指示器红点的位置
                }
            }
        });
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

onScrollStateChangedd的 newState 参数有三种状态SCROLL_STATE_IDLE、SCROLL_STATE_DRAGGING和SCROLL_STATE_SETTLING,分布表示静止状态,拖拽状态和手指离开后的惯性滚动状态。所以这里当RecyclerView的状态为SCROLL_STATE_IDLE时得到当前图片的position,然后与图片列表取余就得到指示器红点的位置。

相关标签: recyclerview