Android ViewPager

ViewPager使用介绍

https://blog.csdn.net/wenzhi20102321/article/details/53584344

ViewPager是个ViewGroup,用于横向分页显示,可以滑动切换页面。如果不需要滑动切换页面可以不用ViewPager。ViewPager必须搭配PagerAdapter使用,PagerAdapter是个抽象类,需要继承实现抽象方法。常用的两个子类是FragmentPagerAdapter和FragmentStatePagerAdapter。当每个Pager都对应一个Fragment时,可以使用这两个子类。具体的用法和注意事项后面再详细介绍。如果每个Pager对应的不是一个Fragment时,需要继承PagerAdapter,实现下面几个方法:

  • instantiateItem(ViewGroup, int)
    初始化一个Pager,ViewGroup参数是ViewPager本身,int参数是Pager所在的位置。这个方法需要生成一个View,并加入到ViewGroup中。并且需要返回一个与该Pager一一对应的对象,通常可以是该Pager的View对象。
  • destroyItem(ViewGroup, int, Object)
    销毁一个Pager,ViewGroup指ViewPager本身,int指Pager所在位置,Object指instantiateItem方法所返回的对象,该方法需要将Pager的View从ViewGroup移除;
  • getCount()
    返回Pager的数量;
  • isViewFromObject(View, Object)
    返回View与Object的对应关系,View是在instantiateItem方法中添加的View,Object是该方法返回的对象;

另外,ViewPager还有两个相对重要的方法:

  • notifyDataSetChanged()
    当页面增加、减少、移动位置时,需要调用此方法。这个方法是否起作用依赖于getItemPosition的返回结果;
  • getItemPosition(Object)
    这个方法默认返回POSITION_UNCHANGED(-1)常量,表示该页的位置没有变化。所以notifyDataSetChanged方法就不会重新加载该页。可以修改这个方法的返回值使得notifyDataSetChanged起作用。可以返回实际位置,或者当Pager被删除后可以返回POSITION_NONE(-2);

另外,一般情况下通过instantiateItem添加的View是没有Id的,这种View在Activity异常后恢复时是不能自动恢复的。

继承PagerAdapter

public class MyPagerAdapter extends PagerAdapter {
    private static final String TAG = MyPagerAdapter.class.getSimpleName();
    private static final boolean DEBUG = true;

    private Context context;
    private List<PagerInfo> pagerInfos = new ArrayList<>();
    private List<MyPager> pagers = new ArrayList<>();

    public MyPagerAdapter(Context context, List<PagerInfo> pagerInfos) {
        if (DEBUG) Log.d(TAG, "Constructor, pager count: " + pagerInfos.size());
        this .context = context;
        this.pagerInfos.addAll(pagerInfos);
        for (int i=0; i<pagerInfos.size(); i++) {
            pagers.add(null);
        }
    }

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

    @Override
    public boolean isViewFromObject(View view, Object object) {
        return view == object;
    }

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        if (DEBUG) Log.d(TAG, "instantiateItem, position: " + position);
        MyPager pager = pagers.get(position);
        if (pager == null) {
            pager = (MyPager)LayoutInflater.from(context).inflate(R.layout.view_my_pager, null);
            pager.updatePager(pagerInfos.get(position));
            pagers.set(position, pager);
        }
        ViewGroup parent = (ViewGroup)pager.getParent();
        if (parent != null) {
            parent.removeView(pager);
        }
        container.addView(pagers.get(position));
        return pagers.get(position);
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        if (DEBUG) Log.d(TAG, "destroyItem, position: " + position);
        container.removeView((MyPager)object);
    }

    @Override
    public int getItemPosition(Object object) {
        MyPager pager = (MyPager)object;
        if (pagers.contains(pager)) {
            return pagers.indexOf(pager);
        } else {
            return POSITION_NONE;
        }
    }

    public void addPager(PagerInfo pagerInfo) {
        if (DEBUG) Log.d(TAG, "addPager, to end, position: " + pagerInfos.size());
        pagerInfos.add(pagerInfo);
        pagers.add(null);
        notifyDataSetChanged();
    }

    public void addPager(int position, PagerInfo pagerInfo) {
        if (DEBUG) Log.d(TAG, "addPager, position: " + position);
        pagerInfos.add(position, pagerInfo);
        pagers.add(position, null);
        notifyDataSetChanged();
    }

    public void removePager(PagerInfo pagerInfo) {
        removePager(pagerInfos.indexOf(pagerInfo));
    }

    public void removePager(int position) {
        if (0 <= position && position < pagerInfos.size()) {
            if (DEBUG) Log.d(TAG, "removePager, position: " + position);
            pagerInfos.remove(position);
            pagers.remove(position);
            notifyDataSetChanged();
        }
    }

    public void updatePager(PagerInfo pagerInfo) {
        updatePager(pagerInfos.indexOf(pagerInfo));
    }

    public void updatePager(int position) {
        if (0 <= position && position < pagerInfos.size()) {
            if (DEBUG) Log.d(TAG, "updatePager, position: " + position);
            PagerInfo pagerInfo = pagerInfos.get(position);
            pagers.get(position).updatePager(pagerInfo);
        }
    }
}

当每个Pager都是Fragment时,可以使用FragmentPagerAdapter时。

  • getItemId(int)
    该方法获取position的Id,默认返回position。参数int是position。Id与position所在的Fragment一一对应,用于在FragmentManager中找到该Fragment。
  • getItem()
    该方法用来获取position所在位置的Fragment。这个方法被instantiateItem方法调用,一般情况下每个Page只会被调用一次。
  • instantiateItem(ViewGroup, int)
    由于Fragment的特殊性(受FragmentManager管控,有自己的生命周期),instantiateItem中首先会通过FragmentManager和Id获取position位置的Fragment,在没有获取到的情况才会调用getItem。所以一般情况下,每个Pager只会调用一次getItem方法。

当页的数量和位置都不改变时可以用Fragment,否则不建议使用。有两点原因:

  • 当页数量或位置发生变化时,一般调用PagerAdapter.notifyDataSetChanged方法,从而触发ViewPager.dataSetChanged回调。在回调中调用Adapter.getItemPosition方法来检查ViewPager保存的所有页对象的位置是否发生变化。所以如果要使Adapter.notifyDataSetChanged方法起作用,一定要重载Adapter.getItemPosition返回实际位置。如果Pager对象位置没有变化,则ViewPager不做处理;如果发生变化,则记录新位置;如果Pager对象不存在了(POSITION_NONE),则调用PagerAdaper.detach。为了使getItemPosition返回的结果准确,Adapter中必须记录所有的Fragment。
  • 在FragmentPagerAdapter.instantiateItem方法中,首先通过getItemId和FragmentManager查找当前Pager的Fragment。由于getItemId默认返回position,所以会找到以前的Fragment。如果需要动态更新Pager,getItemId不能返回position,必须和特定的Fragment绑定。Adpater需要记录所有Fragment的Id,当Pager的数量或位置改变时,对应的Id也需要改变。当Activity异常销毁后恢复时,Fragment也会恢复。对应Fragment的Id也必须能恢复。所以所以异常时需要保存所有Fragment的Id。

下面是一个例子:

继承FragmentPagerAdapter

public class MyFragmentPagerAdapter extends FragmentPagerAdapter {
    private static final String TAG = MyFragmentPagerAdapter.class.getSimpleName();
    private static final boolean DEBUG = true;

    private final String PARAM_ADAPTER = "adapter";
    private final String PARAM_IDS = "ids";
    private final String PARAM_ID = "id";

    private ArrayList<FragmentPagerInfo> pagerInfos = new ArrayList<>();
    private List<MyFragment> fragments = new ArrayList<>();
    private ArrayList<Integer> ids = new ArrayList<>();
    private int id;

    public MyFragmentPagerAdapter(FragmentManager fm) {
        super(fm);
    }

    public MyFragmentPagerAdapter(FragmentManager fm, List<FragmentPagerInfo> pagerInfos) {
        this(fm);
        this.pagerInfos.addAll(pagerInfos);
    }

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        if (DEBUG) Log.d(TAG, "instantiateItem, position: " + position);
        MyFragment fragment = (MyFragment)super.instantiateItem(container, position);
        if (!fragments.contains(fragment)) {
            while(fragments.size() <= position) {
                fragments.add(null);
            }
            if (DEBUG) Log.d(TAG, "instantiateItem, Stored fragment: " + fragment);
            fragments.set(position, fragment);
        }
        return fragment;
    }


    @Override
    public Fragment getItem(int i) {
        if (DEBUG) Log.d(TAG, "getItem, position: " + i);
        while (fragments.size() <= i) {
            fragments.add(null);
        }
        if (fragments.get(i) == null) {
            if (DEBUG) Log.d(TAG, "getItem, create new fragment");
            fragments.set(i,MyFragment.newInstance(pagerInfos.get(i)));
        }
        return fragments.get(i);
    }

    @Override
    public long getItemId(int position) {
        while(ids.size() <= position){
            ids.add(null);
        }
        if (ids.get(position) == null) {
            ids.set(position, id++);
        }
        if (DEBUG) Log.d(TAG, "getItemId, position:" + position + ", id: " + ids.get(position));
        return ids.get(position);
    }

    @Override
    public int getItemPosition(Object object) {
        int position;
        if (fragments.contains(object)) {
            position = fragments.indexOf(object);
        } else {
            position = POSITION_NONE;
        }
        if (DEBUG) Log.d(TAG, "getItemPosition, position: " + position);
        return position;
    }

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

    public void onSaveInstanceState(Bundle outState) {
        if (DEBUG) Log.d(TAG, "onSaveInstanceState");
        Bundle b = new Bundle();
        b.putIntegerArrayList(PARAM_IDS, ids);
        b.putInt(PARAM_ID, id);
        outState.putBundle(PARAM_ADAPTER, b);
    }

    public void onRestoreSavedInstance(Bundle savedInstanceState) {
        if (DEBUG) Log.d(TAG, "onRestoreSavedInstance");
        Bundle b = savedInstanceState.getBundle(PARAM_ADAPTER);
        if (b!=null) {
            ids.clear();
            ids.addAll(b.getIntegerArrayList(PARAM_IDS));
            id = b.getInt(PARAM_ID);
        }
    }

    public void addPager(int position, FragmentPagerInfo pagerInfo) {
        if (DEBUG) Log.d(TAG, "addPager, position: " + position);
        pagerInfos.add(position, pagerInfo);
        fragments.add(position, null);
        ids.add(position, null);
        notifyDataSetChanged();
    }

    public void addPager(FragmentPagerInfo pagerInfo) {
        addPager(pagerInfos.size(), pagerInfo);
    }

    public void removePager(int position) {
        if (DEBUG) Log.d(TAG, "removePager, position: " + position);
        if (0 <= position && position < pagerInfos.size()) {
            pagerInfos.remove(position);
            fragments.remove(position);
            ids.remove(position);
            notifyDataSetChanged();
        }
    }

    public void removePager(PagerInfo info) {
        removePager(pagerInfos.indexOf(info));
    }

    public void updatePager(int position) {
        if (DEBUG) Log.d(TAG, "updatePager, position: " + position);
        if (0 <= position && position < pagerInfos.size()) {
            MyFragment fragment = fragments.get(position);
            if (fragment != null) {
                fragment.updateView(pagerInfos.get(position));
            }
        }
    }

    public void updatePager(FragmentPagerInfo info) {
        int position = pagerInfos.indexOf(info);
        updatePager(position);
    }
}

FragmentStatePagerAdapte和FragmentPagerAdapter的区别

FragmentStatePagerAdapter最多保存三个页面,超出范围的页面会被remove。remove的Fragment不受FragmentManager管控。当页面非常多时,FragmentStatePagerAdapter可以有效降低内存的消耗,付出的代价就是每次切换页面要更多的操作,也就是用时间换取空间。但是对于页面位置或数量的改变与FragmentPagerAdapter有相同的问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值