Android玩转ViewPager(一) 实现循环滚动

循环滚动应用场景还是较多的,这里是支付宝一个例子

这里写图片描述
两个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的懒加载见下篇。

猜你喜欢

转载自blog.csdn.net/qq_36043263/article/details/79680276
今日推荐