看一段简单的代码,在一个pager里面显示两个TextView
List<View> items = new ArrayList<View>();adapter = new MyPagerAdapter();
TextView tv = new TextView(getActivity()); tv.setText("第一页"); items.add(tv); tv = new TextView(getActivity()); tv.setText("第二页"); items.add(tv); pager.setAdapter(adapter);
Adapter代码
class MyPagerAdapter extends PagerAdapter{ @Override public Object instantiateItem(ViewGroup container, int position) { View layout = items.get(position); container.addView(layout); return layout; } @Override public void destroyItem(ViewGroup container, int position, Object object) { View layout = items.get(position); container.removeView(layout); } @Override public boolean isViewFromObject(View arg0, Object arg1) { return arg0 == arg1; } @Override public int getCount() { return items.size(); } @Override public int getItemPosition(Object object) { // TODO Auto-generated method stub return super.getItemPosition(object); } }
代码运行正常,左右滑动都OK。
好,现在需求来了,我需要把“第一页”和“第二页”干掉,再重新添加两个TextView,分别是“第三页”和“第四页”,于是按常理写了如下代码
items.clear(); TextView tv = new TextView(getActivity()); tv.setText("第三页"); items.add(tv); tv = new TextView(getActivity()); tv.setText("第四页"); items.add(tv); adapter.notifyDataSetChanged();我们在使用ListView的时候,改变数据源的数据,然后通知adpater去更新,就可以正常显示,可是在ViewPager这不好使,上面代码执行后,没有任何变化
那我们想是不是ViewPager需要清一下原有的试图呢,好,再加一句
pager.removeAllViews();再次运行,可好,一片空白,啥也没了,真干净!
蒙了吧,到底什么原因,就是getItemPosition,让我看看当ViewPager的Adapter发生变化时,到底干了啥,Adapter执行notifyDataSetChanged时,会触发ViewPager的dataSetChanged方法,下面是源码,:
void dataSetChanged() { // This method only gets called if our observer is attached, so mAdapter is non-null. final int adapterCount = mAdapter.getCount(); mExpectedAdapterCount = adapterCount; boolean needPopulate = mItems.size() < mOffscreenPageLimit * 2 + 1 && mItems.size() < adapterCount; int newCurrItem = mCurItem; boolean isUpdating = false; for (int i = 0; i < mItems.size(); i++) { final ItemInfo ii = mItems.get(i); final int newPos = mAdapter.getItemPosition(ii.object); //看这句话,如果是PagerAdapter.POSITION_UNCHANGED标志,直接返回,不做任何处理 if (newPos == PagerAdapter.POSITION_UNCHANGED) { continue; } //只有返回PagerAdapter.POSITION_NONE标志时,才会对内部视图进行调整 if (newPos == PagerAdapter.POSITION_NONE) { //先从数据源中清除 mItems.remove(i); i--; if (!isUpdating) { mAdapter.startUpdate(this); isUpdating = true; } //在调用Adapter的destroyItem,去销毁视图 mAdapter.destroyItem(this, ii.position, ii.object); needPopulate = true; if (mCurItem == ii.position) { // Keep the current item in the valid range newCurrItem = Math.max(0, Math.min(mCurItem, adapterCount - 1)); needPopulate = true; } continue; } if (ii.position != newPos) { if (ii.position == mCurItem) { // Our current item changed position. Follow it. newCurrItem = newPos; } ii.position = newPos; needPopulate = true; } } if (isUpdating) { mAdapter.finishUpdate(this); } Collections.sort(mItems, COMPARATOR); if (needPopulate) { // Reset our known page widths; populate will recompute them. final int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { final View child = getChildAt(i); final LayoutParams lp = (LayoutParams) child.getLayoutParams(); if (!lp.isDecor) { lp.widthFactor = 0.f; } } setCurrentItemInternal(newCurrItem, false, true); requestLayout(); } }
PagerAdapter.POSITION_UNCHANGED,这个标记决定着视图是否被重新创建,Apdapter默认的代码如下
public int getItemPosition(Object object) { return POSITION_UNCHANGED; }默认返回POSITION_UNCHANGED,所以如果你不对Adapter的getItemPosition进行重写的画,就会出现无法更改内部视图效果的问题。下面对从PagerAdapter继承的代码进行改造,加上对getItemPosition的修改,让他直接返回POSITION_NONE,POSITION_NONE每次数据发生变化,都会引起视图的重建,比较消耗内存,所以不需要变化内部视图时,避免使用。
@Override public int getItemPosition(Object object) { // TODO Auto-generated method stub return POSITION_NONE; }
小插曲
如果返回了POSITION_NONE,但是没有pager.removeAllViews(),那么“第一页”和“第二页”没有消失,“第三页”和“第四页”也上去了,分别和前两页重合了,看图
版权声明:本文为博主原创文章,未经博主允许不得转载。