概述
轮播组件在我们的APP中是很常见的,网上也能找到很多类似的Demo。这里把ViewPager进行了一些封装,支持开发者自定义条目布局,指示点样式,图片加载方式等,耦合低,方便使用。源码:https://github.com/jijinchao2014/CyclePager
对于轮播的原理大概就两种方式:
1.使用Integer的最大值,直接让ViewPager从中间开始轮播,这样可以实现无限轮播,但不是真正意义的无限轮播;
2.使用图片的size+2处理,在原始图片集合的首尾各加1,当ViewPager切换的时候自动进行position修正,这种方式是真正意义的无限轮播。
第一种方式比较简单,这篇小文章主要讲讲第二种的实现思路,这里我自定义了一个CyclePager,继承于ViewPager。
功能
我们先来看看这个自定义ViewPager有哪些功能吧:
- 支持无限轮播;
- 可定制指示点;
- 可定制item的布局;
- 可自定义ViewPager切换效果;
- 支持item点击;
- 按住停止轮播;
- 抬手继续的功能
效果演示
截得图片比较卡顿,实际效果很流畅滴
实现
该实现主要在自定义的CyclePager中,里面进行了简单的封装,本身内部实现了adapter的修正,以及ViewPager切换的修正
代码通过内部重写的setAdapter()和addOnPageChangeListener()将修正adapter和listener进行引用(具体查看代码实现)
adapter修正
相比使用Integer的最大值,这里使用的是图片的size+2的方式实现了真正的无限轮播,如图:
这样,当ViewPager切换D的时候,通过矫正adapter里的position使之后的变成A,当ViewPager在A的时候,使前一个变为D,由于集合长度发生变化,除了以上两种情况,其他的position的位置需要前移一个位置进行修正。
/**
* 修正adapter
*/
public class InnerPagerAdapter extends PagerAdapter {
private PagerAdapter adapter;
public InnerPagerAdapter(PagerAdapter adapter) {
this.adapter = adapter;
}
@Override
public int getCount() {
return adapter.getCount() + 2;
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
if (position == getCount() - 1) {
position = 0;
} else if (position == 0) {
position = adapter.getCount() - 1;
} else {
position -= 1;
}
return adapter.instantiateItem(container, position);
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
adapter.destroyItem(container, position, object);
}
}
listener切换修正
另外,也需要在viewpager切换的时候让静默地切换到修正页面
/**
* 修正listener
*/
public class InnerPageChangeListener implements OnPageChangeListener {
private OnPageChangeListener listener;
private int position;
public InnerPageChangeListener(OnPageChangeListener listener) {
this.listener = listener;
}
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
if (listener != null) {
listener.onPageScrolled(position, positionOffset, positionOffsetPixels);
}
}
@Override
public void onPageSelected(int position) {
this.position = position;
if (listener != null) {
listener.onPageSelected(position);
}
......
}
@Override
public void onPageScrollStateChanged(int state) {
if (position == getAdapter().getCount() - 1) {
CyclePager.this.setCurrentItem(1, false);
} else if (position == 0) {
CyclePager.this.setCurrentItem(getAdapter().getCount() - 2, false);
}
if (listener != null) {
listener.onPageScrollStateChanged(state);
}
}
}
使用
当然,这里给大家封装好了,直接使用即可,使用方法如下:
1.在项目的build.gradle中添加依赖(或者把代码下载后将关键代码复制到自己的项目中):
compile 'com.jijc.cyclepager:cyclepagerlibrary:2.0.2'
2.布局文件中使用CyclePager
<com.jijc.cyclepagerlibrary.view.CyclePager
android:id="@+id/viewpager"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
注意:如果需要添加指示点,则需要使用LinearLayout进行占位,开发者可自定义指示点的形状和显示的位置 只需要自己调整好布局即可(完整布局如下)
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="135dp"
tools:context="com.jijc.cyclepager.MainActivity">
<com.jijc.cyclepagerlibrary.view.CyclePager
android:id="@+id/viewpager"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<LinearLayout
android:visibility="gone"
android:id="@+id/ll_point"
android:orientation="horizontal"
android:layout_width="match_parent"
android:gravity="center_vertical|right"
android:padding="10dp"
android:layout_alignParentBottom="true"
android:layout_height="wrap_content">
</LinearLayout>
</RelativeLayout>
3.Activity或者Frgment中初始化CyclePager并按照需求进行一些必要设置
- 设置指示点,如不需要可不调用
viewpager.addPoints(mContext, R.drawable.bg_pointer1, ll_point, ListUtils.getSize(imgList));
- CyclePager设置数据,详情参考方法注释
viewpager.setImages(mContext, imgList, R.layout.item_cycle_pager, new CyclePager.OnItemInitLisenter() {
@Override
public void initItemView(View view, int position) {
ImageView iv_img = (ImageView) view.findViewById(R.id.iv_img);
TextView tv_play_count = (TextView) view.findViewById(R.id.tv_play_count);
tv_play_count.setText("这是第" + (position + 1) + "个图片");
Object tag = iv_img.getTag();
if (tag == null || !TextUtils.equals((String) tag, imgList.get(position))) {
ImageLoader.loadImageAsync(iv_img, imgList.get(position), DisplayImageOptionsCfg.getInstance().getOptions(R.mipmap.item_live_bg));
iv_img.setTag(imgList.get(position));
}
}
@Override
public void onItemClick(int position) {
Toast.makeText(mContext, "pos:" + (position + 1) + "-url:" + imgList.get(position), Toast.LENGTH_SHORT).show();
}
@Override
public void onItemVisible(int position) {
}
}, 6);
- 设置切换效果,如果想使用默认效果则不必设置
viewpager.setPageTransformer(new DepthPageTransformer());
- 开启自动轮播并设置轮播间隔,如不需要可不调用
viewpager.startRoll(3000);
4.如果启动了自动滚动,开发者想要在某种情况(比如退出页面)停止滚动时可使用如下方法:
viewpager.stopRoll();
好了,到这里一个可以无限轮播的ViewPager就完成了,大家可直接通过as添加依赖进行引用,eclipse可下载代码进行copy,多的不说了,还有更优的方式,望大家多提宝贵意见!