我最近想用ViewPager 来实现类似图片Gallery的效果:即滑动的时候图片一张一张显示!先搜了一下网上关于ViewPager的用法,千篇一律的都是如下的列子:
public class MyPagerAdapter extends PagerAdapter {
List<ImageView> viewList = null;
public MyPagerAdapter(List<ImageView> viewList) {
this.viewList = viewList;
}
@Override
public int getCount() {
return viewList.size();
}
@Override
public boolean isViewFromObject(View arg0, Object arg1) {
return arg0 == arg1;//官方提示这样写
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView(viewList.get(position));//删除页卡
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
container.addView(viewList.get(position));//添加页卡
return viewList.get(position);
}
}
============================================================================
List<ImageView> viewList = new ArrayList<View>();
View view1=LayoutInflater.from(this).inflate(R.layout.test, null);
view1.findViewById(R.id.iv).setBackgroundResource(R.drawable.ic_launcher1);
View view2=LayoutInflater.from(this).inflate(R.layout.test, null);
view2.findViewById(R.id.iv).setBackgroundResource(R.drawable.ic_launcher2);
viewList.add(view1);
viewList.add(view2);
MyPagerAdapter adapter = new MyPagerAdapter(viewList);
ViewPager myViewPager = findViewById(R.id.my_view_pager);
myViewPager.setAdapter(adapter);
上述代码用List<ImageView>记录了所有要显示的图片,然后传给PagerAdapter;如果只有少数几张图片是没有问题的,但是如果要显示100张图片呢?List<ImageView>肯定会导致内存溢出!为什么一定要创建一个List<ImageView>呢,如果所有的ImageView都事先初始化了,这就完全体现不出Adapter View 的高性能!
想一想,其实可以去掉这个List<ImageView>,修改代码如下:
public class IntruderViewPagerAdapter extends PagerAdapter {
private Context mContext;
private List<Integer> mDrawableResIdList;
public IntruderViewPagerAdapter(Context context, List<Integer> resIdList) {
super();
mContext = context;
mDrawableResIdList = resIdList;
}
@Override
public int getCount() {
if (mDrawableResIdList != null) {
return mDrawableResIdList.size();
}
return 0;
}
@Override
public int getItemPosition(Object object) {
if (object != null && mDrawableResIdList != null) {
Integer resId = (Integer)((ImageView)object).getTag();
if (resId != null) {
for (int i = 0; i < mDrawableResIdList.size(); i++) {
if (resId.equals(mDrawableResIdList.get(i))) {
return i;
}
}
}
}
return ViewPager.POSITION_NONE;
}
@Override
public Object instantiateItem(View container, int position) {
if (mDrawableResIdList != null && position < mDrawableResIdList.size()) {
Integer resId = mDrawableResIdList.get(position);
if (resId != null) {
ImageView itemView = new ImageView(mContext);
itemView.setDrawableResource(resId);
//此处假设所有的照片都不同,用resId唯一标识一个itemView;也可用其它Object来标识,只要保证唯一即可
itemView.setTag(resId);
((ViewPager) container).addView(itemView);
return itemView;
}
}
return null;
}
@Override
public void destroyItem(View container, int position, Object object) {
//注意:此处position是ViewPager中所有要显示的页面的position,与Adapter mDrawableResIdList并不是一一对应的。
//因为mDrawableResIdList有可能被修改删除某一个item,在调用notifyDataSetChanged()的时候,ViewPager中的页面
//数量并没有改变,只有当ViewPager遍历完自己所有的页面,并将不存在的页面删除后,二者才能对应起来
if (object != null) {
ViewGroup viewPager = ((ViewGroup) container);
int count = viewPager.getChildCount();
for (int i = 0; i < count; i++) {
View childView = viewPager.getChildAt(i);
if (childView == object) {
viewPager.removeView(childView);
break;
}
}
}
}
@Override
public boolean isViewFromObject(View view, Object object) {
return (view == object);
}
@Override
public Parcelable saveState() {
return null;
}
@Override
public void restoreState(Parcelable state, ClassLoader loader) {
}
@Override
public void startUpdate(View container) {
}
@Override
public void finishUpdate(View container) {
}
public void updateData(List<Integer> itemsResId) {
if (itemsResId == null) {
return;
}
mDrawableResIdList = itemsResId;
this.notifyDataSetChanged();
}
}
上面代码主要修改就是:
- 在需要创建页面instantiateItem() 的时候才去加载图片,从而不需要List<ImageView>事先加载所有的图片,
- 并且给每个ItemView设置Tag来唯一标识,这样在调用PagerAdapter.getItemPosition() 的时候通过Tag来获取item的位置
void dataSetChanged() {
boolean needPopulate = mItems.isEmpty() && mAdapter.getCount() > 0;
int newCurrItem = -1;
for (int i = 0; i < mItems.size(); i++) {
final ItemInfo ii = mItems.get(i);
final int newPos = mAdapter.<span style="background-color: rgb(255, 255, 102);">getItemPosition</span>(ii.object);
if (<span style="background-color: rgb(255, 255, 102);">newPos == PagerAdapter.POSITION_UNCHANGED</span>) {
continue;
}
if (<span style="background-color: rgb(255, 255, 102);">newPos == PagerAdapter.POSITION_NONE</span>) {
mItems.remove(i);
i--;
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, mAdapter.getCount() - 1));
}
continue;
}
if (<span style="background-color: rgb(255, 255, 102);">ii.position != newPos</span>) {
if (ii.position == mCurItem) {
// Our current item changed position. Follow it.
newCurrItem = newPos;
}
ii.position = newPos;
needPopulate = true;
}
}
if (newCurrItem >= 0) {
// TODO This currently causes a jump.
setCurrentItemInternal(newCurrItem, false, true);
needPopulate = true;
}
if (needPopulate) {
populate();
requestLayout();
}
}
上面代码来自ViewPager.java,其中ArrayList<ItemInfo> mItems 用来记录ViewPager所有要显示的页面,我们发现mItems与PagerAdapter 中的DataList 并不是同步的,所以二者不是一一对应的。
其实在调用PagerAdapter.notifyDataSetChanged()的时候,ViewPager会遍历mItems,通过PagerAdapter.getItemPosition()来判断当前页面是否存在或者位置有改变,从而刷新屏幕!