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()方法。 
   
这里滑动用到了LinearSmoothScroller,继续点击去,里面有一个calculateSpeedPerPixel()方法。 

  官方注释:计算滚动速度。如果返回值是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,然后与图片列表取余就得到指示器红点的位置。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值