前言
最近在做项目的时候,有个需求就是实现自动轮播式的ViewPager,最直观的例子就是知乎日报顶部的ViewPager,它内部有着好几个子view,每个一段时间便自动滑动到下一个item view,而底部的指示器也随之跟着改变。使用这种ViewPager的好处是在有限的空间内可以展示出多样化的信息。轮播式ViewPager广泛应用于各种应用内部,用于展示广告等。抱着学习和分享的目的,笔者把轮播式ViewPager写成了一个独立的控件,以方便以后的使用。
效果展示
话不多说,我们先来看看实现的效果是怎样的:
从上面的动态图可以看到,当我们手指拖动ViewPager的时候,下方的指示器随着页面的滑动而滑动,当点击添加数据的按钮的时候,ViewPager的数据项变多,同时下方的指示器也随之改变,适应了数据项的数目。
从上面的动态图可以看到,当我们不用手指进行拖动的时候,该ViewPager会每隔4s左右的时间自动进行滚动,滚动到最后一个item view的时候,下一次会滚到第一个位置。
GitHub地址及使用介绍
读者可以直接到我的GitHub中获取源码。
GitHub:BannerViewPager,控件及其相关文件都放在了该目录下的library模块内,而app模块则是上面效果展示的一个简单应用。
通过以下几个步骤,就能方便地使用该控件了:
1、像普通的ViewPager一样,在布局文件中放入该控件如下:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.chenyu.library.bannerViewPager.BannerViewPager
android:id="@+id/banner"
android:layout_width="match_parent"
android:layout_height="200dp">
</com.chenyu.library.bannerViewPager.BannerViewPager>
<!-- others -->
</LinearLayout>
2、获取BannerViewPager的实例,进行相应的配置,比如我们使用ViewPager的时候,也需要设置它的适配器等。这里笔者实现了一个ViewPagerAdapter,用作BannerViewPager的适配器:
//获取BannerViewPager实例
bannerViewPager = (BannerViewPager) findViewById(R.id.banner);
//实例化ViewPagerAdapter,第一个参数是View集合,第二个参数是页面点击监听器
mAdapter = new ViewPagerAdapter(mViews, new OnPageClickListener() {
@Override
public void onPageClick(View view, int position) {
Log.d("cylog","position:"+position);
}
});
//设置适配器
bannerViewPager.setAdapter(mAdapter);
和一般的ViewPager没什么两样,都是:获取实例——创建适配器——设置适配器。而适配器的数据集一般都是一个View集合,用作ViewPager的item view,所以需要事先准备好相应的View集合。此外,一般轮播式ViewPager点击某一项后会打开相应的页面,所以这里提供了一个OnPageClickListener的监听器,在创建适配器的时候同时创建该监听器即可。
原理简析
接下来,笔者将简要分析BannerViewPager的实现思路,具体的请读者参考源码~
实现自动滚动
首先,我们先思考一下,系统自带的ViewPager是一个独立控件,没有指示器,也没有自动滚动的功能,但是它是一个现成的,可左右滑动的控件,我们肯定是需要ViewPager的,因此,我们可以利用一个布局,把ViewPager包裹起来,同时在这个布局里面再放入indicator(指示器)。
那么,第一步,先新建BannerViewPager.java继承自FrameLayout,而这个FrameLayout有两个子元素:ViewPager和indicator。至于indicator,下面会说到。在构造函数内对这两个控件进行初始化先:
public class BannerViewPager extends FrameLayout implements ViewPager.OnPageChangeListener {
private ViewPager mViewPager;
private ViewPagerIndicator mIndicator;
private ViewPagerAdapter mAdapter;
//...
public BannerViewPager(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.mContext = context;
initViews();
}
private void initViews() {
//initialize the viewpager
mViewPager = new ViewPager(mContext);
ViewPager.LayoutParams lp = new ViewPager.LayoutParams();
lp.width = ViewPager.LayoutParams.MATCH_PARENT;
lp.height = ViewPager.LayoutParams.MATCH_PARENT;
mViewPager.setLayoutParams(lp);
//initialize the indicator
mIndicator = n