ViewPager使用详解

本文详细介绍了ViewPager的使用,包括基本的ViewPager+PageAdapter,结合FragmentPagerAdapter和TabLayout的使用,以及如何实现无限轮播和同屏多页展示。在实现过程中,还探讨了FragmentPagerAdapter和FragmentStatePagerAdapter的选择策略,以及手动实现轮播的关键代码和注意事项。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这两天看了鸿洋大神的一篇关于ViewPager的推送,将其中的内容实现了下,过程中依旧踩坑不断,现在将填坑过程中的一些解决方法及理解记录一下。

ViewPager+PageAdapter

这是最基本的一种使用,要注意的是,PagaAdapter中有4个必须要重写的方法:
- getCount()
需要在viewpager中显示的对象数。
- isViewFromObject(View view, Object object)
直接return view==object;
- instantiateItem(ViewGroup container, int position)
要显示页面的初始化,其中return 语句中返回的object才是显示的内容。
- destroyItem(ViewGroup container, int position, Object object)
页面不是当前显示页面,也不是缓存页面,则回调该方法将其销毁。

ViewPager+FragmentPagerAdapter+TabLayout

这里写图片描述
用FragmentPagerAdapter的话,通常重写两个方法:

@Override
           public Fragment getItem(int position) {
               return list.get(position);
           }

           @Override
           public int getCount() {
               return list.size();
           }

这里要注意的是,在new一个FragmentPagerAdapter时,需要传入一个FragmentManager,而这个FragmentManager是v4包中的,它的获取方式是

fragmentManager=getSupportFragmentManager();

而不是常用的 fragmentManager1=getFragmentManager();
我们用fragment时因为它能实现更多的逻辑,降低耦合性,而用view的话,也可以进行某些实现,但是代码就会全部冗杂在一块儿,后面如果修改就会很麻烦。
我们可以结合TabLayout实现页面滑动时上层标签的内容改变。
1.重写adapter中的getPageTitle()方法,它的返回值即标签中的内容

@Override
            public CharSequence getPageTitle(int position) {
                switch (position){
                    case 0:return "first";
                    case 1:return "second";
                    case 2:return "third";
                    default:return "hello";
                }
           }

这里case后不需要break了,因为用了return离开了该方法,也不需要用switch语句后用return,因为有default语句,不管是否有符合的值,都会return。
2.将ViewPager与TabLayout“绑定”

tabLayout.setupWithViewPager(viewPager);

当两者绑定后,其实是TabLayout通过ViewPager调用它的getPageTitle()方法来实现联动。
这里有一个知识点,就是FragmentPagerAdapter与FragmentStatePagerAdapter的区别,鸿洋大神写得很清楚了,这里就直接引用了。

FragmentPagerAdapter:对于不再需要的 fragment,选择调用 onDetach() 方法,仅销毁视图,并不会销毁 fragment 实例。
FragmentStatePagerAdapter:会销毁不再需要的 fragment,当当前事务提交以后,会彻底的将 fragmeng 从当前 Activity 的FragmentManager 中移除,state 标明,销毁时,会将其 onSaveInstanceState(Bundle outState) 中的 bundle 信息保存下来,当用户切换回来,可以通过该 bundle 恢复生成新的 fragment,也就是说,你可以在 onSaveInstanceState(Bundle outState) 方法中保存一些数据,在 onCreate 中进行恢复创建。

总结起来就是:当页面多的时候,就用FragmentStatePagerAdapter来省内存;页面少时,就用FragmentPagerAdapter来提升效率。

ViewPager的轮播

1.自动无限轮播
即在一定时间间隔时更换页面,这里通过handler就可以实现了。

 Handler handler=new Handler(){
            @Override
            public void handleMessage(Message msg) {
                if (msg.what==0011){
                    viewPager.setCurrentItem((viewPager.getCurrentItem()+1)%list.size());
                    this.sendEmptyMessageDelayed(0011,1000);
                }
            }
        };
        handler.sendEmptyMessageDelayed(0011,1000);

2.手动实现轮播
所谓的手动实现轮播,就是在最后一个页面往后滑动时可以回到第一个页面。而这也是与banner很大的一个区别,banner是可以直接实现的,而viewpager我们则需要写一些内容。
先上代码:

@Override
            public int getCount() {
                return Integer.MAX_VALUE;
            }

            @Override
            public Object instantiateItem(ViewGroup container, int position) {

                View view=list.get(position%list.size());
                ViewGroup viewGroup=(ViewGroup)view.getParent();
                if (viewGroup!=null) viewGroup.removeView(view);
                container.addView(view);
                return view;
            }

            @Override
            public void destroyItem(ViewGroup container, int position, Object object) {}

因为我们要实现“从尾到头”的变化,而这个变化也不知道要多少次,所以我们就通过getCount()给了一个绝对大的值来实现。
重点在instantiateItem()中,如果我们按照之前的写法,即

@Override
            public Object instantiateItem(ViewGroup container, int position) {
                View view=list.get(position);
                container.addView(view);
                return  view;
            }

            @Override
            public void destroyItem(ViewGroup container, int position, Object object) {
                container.removeView(list.get(position));
            }

我们会发现当往回滑动的时候,程序会崩掉,这是因为图片第一次加载了,当往回滑动,它再一次加载时,我们需要在它的父类中先将该object删除了,再重新加载新的对象。
这里还有一个要注意的是,因为我们在instantiateItem()中已经对图片的移除做了处理了,所以就不需要重写destroyItem()方法了。如果我们按照上面的代码重写了该方法,会发现显示的内容为空。

ViewPager中滑动页面后文字改变

我们可以选择在instantiateItem()中根据当前的position来获得文字内容,但这样滑动时会显得比较生硬,所以可以选择将textview与ViewPager分离开,通过对ViewPager添加监听,来达到页面变化时文字内容改变。

viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {}

            @Override
            public void onPageSelected(int position) {
                  textView.setText(titles[position%titles.length]);
            }

            @Override
            public void onPageScrollStateChanged(int state) {}
        });

同屏显示多个页面

这里的同屏显示多个页面,并不是ViewPager中显示多个,实际上它还是只显示了一个页面,但是我们通过它与其父布局及它与前后两个页面之间的margin来达到3个页面(部分页面)的同时出现。需要用到的几个方法:
- clipChildren=”false”
设定值为false后,才可以使得子view的裁剪不受影响
- viewPager.setPageMargin( )
设置每两个页面之间的margin
- viewPager.setOffscreenPageLimit( )
设置需要显示在屏幕上的页面的个数
这里贴出xml的布局:

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:clipChildren="false">

<android.support.v4.view.ViewPager
    android:id="@+id/viewpagers"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:clipChildren="false"
    android:layout_gravity="center"
    android:layout_marginLeft="60dp"
    android:layout_marginRight="60dp" />
</LinearLayout>

当我们实现多屏显示后,如果觉得单调,想让页面随着滑动的位置不同,改变图片的透明度,可以调用viewPager.setPageTransformer( )来增加特效。

viewPager.setPageTransformer(false, new ViewPager.PageTransformer() {
            private static final float DEFAULT_MIN_ALPHA = 0.5f;
            private float mMinAlpha = DEFAULT_MIN_ALPHA;
            @Override
            public void transformPage(View page, float position) {
                if (position < -1)
                {
                    page.setAlpha(mMinAlpha);
                } else if (position <= 1)
                { // [-1,1]

                    if (position < 0) //[0,-1]
                    {
                        float factor = mMinAlpha + (1 - mMinAlpha) * (1 + position);
                        page.setAlpha(factor);
                    } else//[1,0]
                    {
                        float factor = mMinAlpha + (1 - mMinAlpha) * (1 - position);
                        page.setAlpha(factor);
                    }
                } else
                { // (1,+Infinity]
                    page.setAlpha(mMinAlpha);
                }
            }
        });

关于这个动画,还可以看下大神的另一篇文章
巧用ViewPager 打造不一样的广告轮播切换效果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值