Day3(上) 一篇文章带你吃透ViewPager的三大用法及刷新问题

本文详述ViewPager的使用,包括基础概念、适配器实现、翻页动画,重点探讨了数据刷新问题及其多种解决方案,如PagerAdapter、FragmentPagerAdapter、FragmentStatePagerAdapter的刷新策略,以及在“爱阅”项目中的实践应用。

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

今天我们来一起实现“爱阅”首页滑动切换分类浏览阅读的效果,并将ViewPager和TabLayout结合起来用以实现顶部导航栏的分类展示,并增加点击快速切换分类的功能。ViewPager+TabLayout也是当前最炙手可热的组合方式,我会首先对基础的知识点做一些讲解,然后对我们今天的内容进行实现。

首先看一下效果图:

点此进入目录:[干货] 十天 教你从创意到上线APP

1、ViewPager简介

ViewPager是android扩展包v4包中的类,这个类可以让用户左右切换当前的view
- ViewPager类直接继承了ViewGroup类,所以它是一个容器类,可以在其中添加其他的view类。
- ViewPager类需要一个PagerAdapter适配器类给它提供数据。
- ViewPager经常和Fragment一起使用,并且提供了专门的FragmentPagerAdapter和FragmentStatePagerAdapter类供Fragment中的ViewPager使用。

2、ViewPager的适配器

上文的简介中提到了PagerAdapter,其实和RecyclerView、ListView等控件使用一样,ViewPager需要设置PagerAdapter来完成页面和数据的绑定,这个PagerAdapter是一个基类适配器,我们经常用它来实现App引导图,它的子类有FragmentPagerAdapter和FragmentStatePagerAdapter,这两个子类适配器用于和Fragment一起使用,在安卓应用中它们就像RecyclerView一样出现的频繁。

(1)实现一个最基本的PagerAdapter
    public class AdapterViewpager extends PagerAdapter {
   
        private List<View> mViewList;

        public AdapterViewpager(List<View> mViewList) {
            this.mViewList = mViewList;
        }

        @Override
        public int getCount() {
  //必须实现
            return mViewList.size();
        }

        @Override
        public boolean isViewFromObject(View view, Object object) {
  //必须实现
            return view == object;
        }

        @Override
        public Object instantiateItem(ViewGroup container, int position) {
  //必须实现,实例化
            container.addView(mViewList.get(position));
            return mViewList.get(position);
        }

        @Override
        public void destroyItem(ViewGroup container, int position, Object object) {
  //必须实现,销毁
            container.removeView(mViewList.get(position));
        }
    }
  • instantiateItem()
    可以看到instantiateItem()做了两件事,第一:将当前视图添加到container中,第二:返回当前View。也就是说instantiateItem()的功能是创建指定位置的页面视图,并且适配器有责任增加即将创建的View视图添加到这里给定的container中。它的返回值代表新增视图页面的Object(Key),这里没必要非要返回视图本身,也可以返回可以代表当前页面的任意值,只要你可以与你增加的View一一对应即可,比如position变量也可以做为Key。

  • isViewFromObject()
    该函数用来判断 instantiateItem() 函数所返回来的 Key 与一个页面视图是否是代表的同一个视图(即它俩是否是对应的,对应的表示同一个 View),如果对应的是同一个View回 true,否则返回 false。

  • destroyItem()
    该方法的功能是移除一个给定位置的页面,适配器有责任从容器中删除这个视图,这是为了确保在 finishUpdate(viewGroup) 返回时视图能够被移除。

不过说道destroyItem()这个方法的时候就不得不提及ViewPager的刷新问题了,因为ViewPager的刷新并不是我们最初想的调用一下notifyDataSetChanged()就完事了这么简单的,我们会在后文说明“爱阅”中遇到的坑和解决办法。

(2)实现一个最基本的FragmentPagerAdapter
/**
 * Created by   : WGH.
 */
public class ViewPagerAdapter extends FragmentPagerAdapter {
   
    private ArrayList<Category> mCategoryList;
    private Context mContext;
    private Fragment mFragment;

    public ViewPagerAdapter(FragmentManager fm, Context context) {
        super(fm);
        mContext = context;
        mCategoryList = DataCacheHelper.getInstance().getPagerChildCategories();
    }

    public void onCategorysChange(String key) {
        if (key != null) {
            mCategoryList = DataCache.getInstance().getChildCategorys(key);
            notifyDataSetChanged();
        } else {
            DLog.e("onCategorysChange() Error!");
        }
    }

    @Override
    public Fragment getItem(int position) {
  // 必须实现
        return ViewPagerFragment.newInstance(mContext, mCategoryList.get(position));
    }

    @Override
    public int getCount() {
  // 必须实现
        if (mCategoryList != null) {
            return mCategoryList.size();
        } else {
            return 0;
        }
    }

    @Override
    public CharSequence getPageTitle(int position) {
  // 选择性实现
        return mCategoryList.get(position).getName();
    }

    public String getFragmentTag(int viewPagerId, int fragmentPosition) {
        return "android:switcher:" + viewPagerId + ":" + fragmentPosition;
    }

    public String getFragmentTag(int viewPagerId, int fragmentPosition) {
        return "android:switcher:" + viewPagerId + ":" + fragmentPosition;
    }

    @Override
    public int getItemPosition(Object object) {
        return POSITION_NONE;
    }
}

FragmentStatePagerAdapter的实现和FragmentPagerAdapter的实现一样就不在写了。而这里的getItemPosition()之所以这样写同样和ViewPager的刷新有关,我们后文讲解。

三个适配器的区别:

PagerAdapter是基类适配器是一个通用的ViewPager适配器,相比PagerAdapter,FragmentPagerAdapter和FragmentStatePagerAdapter更专注于每一页是Fragment的情况,而这两个子类适配器使用情况也是有区别的。FragmentPagerAdapter适用于页面比较少的情况,FragmentStatePagerAdapter适用于页面比较多的情况,我们可以从两个适配器的源码得知。

  • FragmentStatePagerAdapter
@Override
  public Object instantiateItem(ViewGroup container, 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值