一天一Android之ViewPager
ViewPager
在开发中使用的频率非常的高,例如Banner
轮播图,首次启动显示的介绍图等,这篇博客就详细介绍一下ViewPager
的使用。
PagerAdapter
ViewPager
和ListView
一样,也需要一个Adapter
,即PagerAdapter
,我们先来看看都有哪些方法可以实现:
|
其实大部分方法我们都不需要实现。
轮播图
接下来,就基于ViewPager
撸一个无限滚动轮播图。先看运行效果:
先说一下我们的大概思路,这里一共创建了三个类,继承于RelativeLayout
的BannerView
,继承于PagerAdapter
的BannerPageAdapter
和一个继承于Runnable
的工具类WeakRunnable
,只所以要创建一个WeakRunnable
类,是因为防止内存泄露。因为轮播图会无限循环,这里会使用Handler
无限执行。然后拦截BannerView
触摸事件,来停止或者开启循环。
WeakRunnable
先来看看WeakRunnable
:
|
这里的代码很简单,定义了一个接口WeakRunnableEventListener
,并且声明一个弱引用,来持有实现了WeakRunnableEventListener
接口的类,并且在run
方法中判断这个类是否还存在,如果存在,就回调weakRunnableEventCallBack
方法五执行具体的任务代码。
BannerPageAdapter
因为ViewPager
需要一个PagerAdapter
来决定如何显示,所以,我们这里创建类BannerPageAdapter
继承于PagerAdapter
,代码如下:
|
代码也很简单,
在构造方法中,我们初始化了一个用于缓存ImageView
的集合。
重写了父类的notifyDataSetChanged
,这里我们追加一个数据源集合,并调用父类的方法,来刷新数据。
在getCount
方法中,如果数据源为空,或者数据源的数量为空,返回0,否则返回最大数,因为我们要做无限轮播。
在instantiateItem
方法中,首先算出真正的位置,直接position%mRealSize
就可以得到当前的位置,然后去缓存集合中取ImageView
,如果mCacheImageViews
中没有缓存的ImageView
,那么直接创建ImageView
,并设置点击事件的监听者为自己。如果缓存中有,直接取出来使用,这里使用Glide
来加载网络图片,记住,使用Glide
就不能使用setTag
,这里使用setId
。最后一点,一定要将ImageView
添加到container
中。
在destroyItem
方法中,我们将销毁的Imageview
添加到缓存中,以备下次使用。
最后,在点击事件中,回调监听者。
BannerView
再来看我们的BannerView
,继承于RelativeLayout
,内部持有一个ViewPager
,一个BannerPageAdapter
,一个WeakRunnable
,代码也很简单:
|
首先,在构造方法中,初始化ViewPager
,设置Adapter
,初始化事件等。
在重新设置数据源以后,通知Adapter
更新数据,并设置ViewPager
的当前项。最主要的是onPageSelected
方法和dispatchTouchEvent
方法,在onPageSelected
方法中,我们需要修改当前指示器。在dispatchTouchEvent
方法中,我们需要监听触摸手势,如果当前手势为按压,我们要停掉滚动,如果离开,我们再次开启。
在Activity
中这样使用:
|
|
至此,一个无限滚动轮播图就好了。
FragmentPageAdapter
通常情况下,除了PagerAdapter
,我们还可以使用它的两个子类:FragmentStatePagerAdapter
和FragmentPagerAdapter
,从名字我们就可以看出,这两个适配器主要是针对Fragment
的。我们先来看看FragmentPagerAdapter
是如何使用的:
|
不难看出,FragmentPagerAdapter
只需要我们实现三个方法,一个构造方法,一个getCount()
返回几项,getItem(int position)
返回具体的Fragment
。也用法也是很简单的。
FragmentStatePagerAdapter
和FragmentPagerAdapter
用法一样,只是他们内部缓存的策略不是很一样FragmentStatePagerAdapter
会在destroyItem
中将已经消失的Fragment
移除出去,所以他会一直调用getItem
来创建,而FragmentPagerAdapter
则不会,所以,如果我们的页数比较多的时候,建议使用FragmentStatePagerAdapter
,并做适当的缓存策略,防止一直创建Fragment
。