循环滚动应用场景还是较多的,这里是支付宝一个例子
两个ImageVIew并提供了自动轮播以及手动无限翻页的功能。
先总结一下VIewPager的基础。
ViewPager是什么
继承了ViewGroup所以本身用于存放View,而自动翻页的特效无非就是自身Canvas的移动,通过Scroll来实现。
PagerAdapter是什么
PagerAdapter称ViewPager的适配器,为什么叫适配器呢,一种设计模式其实就是提供了相关的View给ViewPager,在ViewPager展示很多内容情况下如果将所有的View都添加到ViewPager上,则给内存带来了不必要的开销,所以ViewPager有个缓存机制,每次从PagerAdapter拿取设定数量的View,随着用户滑动而不断地销毁本身已展示过的View并从PagerAdapter拿取新的View。而PagerAdapter本身为抽象类,所以详见它的具体实现类。
PagerAdapter的具体实现类
myPagerAdapter extends PagerAdapter
我们自定义一个类直接继承它并实现抽象方法
public class myPagerAdapter extends PagerAdapter {
@Override
public int getCount() {
return 0; //告诉ViewPager有多少View需要展示
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object; //确定一个页面视图是否关联到一个特定的对象,一般返回这个判断
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
//这里的container则是ViewPager本身,position是当前需要展示View的位置
{......我们的代码}
//在这里我们将View添加到ViewPager
//所以当ViewPager需要新的View的情况下就会调用这个方法
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
super.destroyItem(container, position, object);
{....我们的代码}
//于此相对销毁展示过的View调用这个方法, position为需要销毁View的位置
}
}
FragmentPagerAdapter
官方实现的一个可以添加Fragment的ViewPager适配器,当然我们也需要再次继承它来放入Fragment。
public class myFragementAdapter extends FragmentPagerAdapter {
public myFragementAdapter(FragmentManager fm) {
super(fm);
//操作Fragment必然需要一个FragmentManager
}
@Override
public Fragment getItem(int position) {
{.....我们的代码}
//同上ViewPager需要的Fragment从这里获取,position为需要展示的位置
}
@Override
public int getCount() {
return 0; //需要展示Fragment的数量
}
}
可以看到使用这个适配器我们的代码量是很少的,只需要提供相对应的Fragment即可,而具体的添加移除细节我们则不用考虑。
具体加载方法适配器本身已经做到了
FragmentStatePagerAdapter
public class myFragementAdapter extends FragmentStatePagerAdapter {
public myFragementAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int position) {
}
@Override
public int getCount() {
return 0;
}
}
方法竟与FragmentPagerAdapter完全一样? 没错FragmentPagerAdapter与FragmentStatePagerAdapter都是实现了ViewPager加载Fragment,只是加载的机制不同,前者在内部会有一个缓存机制,也就是说不同的Fragment只调用一次getItem(int position)方法,当前页面超过了ViewPager本身的加载数量后不对其进行销毁,具体可自行百度Fragment的生命周期。所以用这个适配器时可在Fragment内部缓存View即缓存我们对View的操作,所以一般常用app的主界面。而后者体现在销毁上,当偏离了ViewPager加载的数量后对其Fragment进行销毁,所以再次需要Fragment时又要重新调用getItem(int position)方法,因此用这个适配器在Fragment内部不能缓存View,所以常用展示量较大的场景。
ViewPager.PageTransformer
该接口主要规定了ViewPager在切换View这个过程中多次调用的方法,其实就是动画的实现方法
public class fadeInFadeOut implements ViewPager.PageTransformer {
@Override
public void transformPage(View page, float position) {
if(position<1&&position>0){
page.setAlpha(1-position);
}
else if(position>-1&&position<0){
page.setAlpha(1+position);
}
}
}
这是笔者演示定义的一个简单例子,这个方法提供了两个参数(page:VIewPager指定加载(缓存)几个View后,这些View都会被分别传入进来,position:这个position不同于适配器的position,这个是根据View的顺序以及在屏幕中展示的位置来确定的)
笔者方便说明画了个图,这个ViewPager宽度刚好被两个View所填充,那么此时View1的postion为-1,view2为-0.5,view3为0,view4为0.5,也就是说当一个View刚好碰到ViewPager的left时候值为0,碰到right时候值为1,在其内部则为0-1,假定ViewPager缓存的VIew为无穷大,那么最左边的postion为负无穷大,右边为正无穷大。所以我们可以根据滑动过程传入的值来自定义我们想要的动画了。
ViewPager的循环滑动
实现循环滑动则需要做到将相同的View在不同的position展示出来即可,所以我们用到FragmentStatePagerAdapter
实现FragmentStatePagerAdapter
public class myFragementAdapter extends FragmentStatePagerAdapter {
List<Fragment> list; //方便起见我们直接创建一个List,List其实对于PagetAdapter是没有意义的
public myFragementAdapter(FragmentManager fm, List<Fragment> li) {
super(fm);
list = li; //在构造函数中传入包含一定数量的Fragment的List
}
@Override
public Fragment getItem(int position) {
return list.get(position % list.size()); //当读取到集合最后一位时又从第一位开始读取。
}
@Override
public int getCount() {
return Integer.MAX_VALUE;
}
}
配置VIewPager
public class MainActivity extends AppCompatActivity {
ViewPager viewPager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
viewPager = (ViewPager) findViewById(R.id.packager); //找到ViewPager对象
int[] ints = {R.mipmap.one, R.mipmap.two, R.mipmap.there, R.mipmap.four}; //定义一个图片资源地址数组用于产生不同的IamgeView
List<android.support.v4.app.Fragment> list = ImageViewUtil.getFragmentList(this, ints); //笔者定义的一个工具类,主要就是传入资源数组生成一个包裹Fragment的List
myFragementAdapter myPagerAdapter = new myFragementAdapter(getSupportFragmentManager(), list);
viewPager.setOffscreenPageLimit(1); //设置ViewPager的加载(缓存)数量,默认为1,指的同时加载超出ViewPager外的View左右两端数量各为1.
viewPager.setAdapter(myPagerAdapter);
viewPager.setPageTransformer(true, new fadeInFadeOut()); //自定义的翻页动画
}
}
看下效果图
是不是可以多次看到这个小美女相同的照片了。 ok,手动循环滚动就搞定了,自动的无非就是多加行代码而已,
handler.postDelayed(new Runnable() {
@Override
public void run() {
viewPager.setCurrentItem(viewPager.getCurrentItem() + 1);
handler.postDelayed(this, 2000);
}
}, 2000);
viewPager.setCurrentItem()
这个方法用于设定ViewPager的显示位置,虽说有动画效果不过速度较快,需要修改速度就要用到反射改变ViewPager内部的Scroller,具体自行百度。
ViewPager+Fragment的懒加载见下篇。