1. SDK讲解
提供一个适配器用于填充ViewPager页面. 你很可能想要使用一个更加具体的实现, 例如: FragmentPagerAdapter
or FragmentStatePagerAdapter
.
当你实现一个PagerAdapter时,至少需要覆盖以下几个方法:
instantiateItem(ViewGroup, int)
destroyItem(ViewGroup, int, Object)
getCount()
isViewFromObject(View, Object)
PagerAdapter比AdapterView的使用更加普通.ViewPager使用回调函数来表示一个更新的步骤,而不是使用一个视图回收机制。在需要的时候pageradapter也可以实现视图的回收或者使用一种更为巧妙的方法来管理视图,比如采用可以管理自身视图的fragment。
看上面的翻译,与我们相关只有这两段话:
viewpager不直接处理每一个视图而是将各个视图与一个键联系起来。这个键用来跟踪且唯一代表一个页面,不仅如此,该键还独立于这个页面所在adapter的位置。当pageradapter将要改变的时候他会调用startUpdate函数,接下来会调用一次或多次的instantiateItem或者destroyItem。最后在更新的后期会调用finishUpdate。当finishUpdate返回时 instantiateItem返回的对象应该添加到父ViewGroup destroyItem返回的对象应该被ViewGroup删除。methodisViewFromObject(View, Object)代表了当前的页面是否与给定的键相关联。
对于非常简单的pageradapter或许你可以选择用page本身作为键,在创建并且添加到viewgroup后instantiateItem方法里返回该page本身即可destroyItem将会将该page从viewgroup里面移除。isViewFromObject方法里面直接可以返回view == object。
对于上面两段话,我这里有两点要着重讲一下:
1、第一段说明了,键(Key)的概念,首先这里要清楚的一点是,每个滑动页面都对应一个Key,而且这个Key值是用来唯一追踪这个页面的,也就是说每个滑动页面都与一个唯一的Key一一对应。大家先有这个概念就好,关于这个Key是怎么来的,下面再讲。
2、第二段简单讲了一个应用,即将当前页面本身的View作为Key。其实这个应用就是我们前一章讲的例子应用。不太理解?没关系,下面细讲。下面我们讲讲Key的问题
2.2 详解KEY
instantiateItem (ViewGroup container, int position)
public Object instantiateItem (ViewGroup container, int position)
Create the page for the given position. The adapter is responsible for adding the view to the container given here, although it only must ensure this is done by the time it returns fromfinishUpdate(ViewGroup)
.
返回值:返回一个代表新增视图页面的Object(Key),这里没必要非要返回视图本身,也可以这个页面的其它容器。其实我的理解是可以代表当前页面的任意值,只要你可以与你增加的View一一对应即可,比如position变量也可以做为Key(最后我们举个例子试试可不可行)
心得 :
1、从说明中可以看到,在代码中,我们的责任是将指定position的视图添加到conatiner中
2、Key的问题:从这个函数就可以看出,该函数返回值就是我们根据参数position增加到conatiner里的View的所对应的Key!!!!!!!
3、“it only must ensure this is done by the time it returns fromfinishUpdate(ViewGroup).”这句话在destroyItem()的函数说明中同样出现过,这说明在 finishUpdate(viewGroup)执行完后,有两个操作,一个是原视图的移除(不再显示的视图),另一个是新增显示视图(即将显示的视图)上一章示例代码:
@Override
public Object instantiateItem(ViewGroup container, int position) {
// TODO Auto-generated method stub
container.addView(viewList.get(position));
return viewList.get(position);
}
};
在这里,我们做了两件事
第一:将参数里给定的position的视图,增加到conatiner中,供其创建并显示、。
第二:返回当前position的View做为此视图的Key。还记得API官方文档中下面这段话么?
对于非常简单的pageradapter或许你可以选择用page本身作为键,在创建并且添加到viewgroup后instantiateItem方法里返回该page本身即可destroyItem将会将该page从viewgroup里面移除。isViewFromObject方法里面直接可以返回view == object。
这里就把当前的View当作Key传过出去!!!!
isViewFromObject (View view, Object object)
public abstract boolean isViewFromObject (View view, Object object)
Determines whether a page View is associated with a specific key object as returned by instantiateItem(ViewGroup, int)
. This method is required for a PagerAdapter to function properly.
返回值:如果对应的是同一个View,返回True,否则返回False。
在上章节的例子中,我们这样做的:
@Override
public boolean isViewFromObject(View arg0, Object arg1) {
// TODO Auto-generated method stub
return arg0 == arg1;
}
由于在instantiateItem()中,我们作为Key返回来的是当前的View,所以在这里判断时,我们直接将Key与View看是否相等来判断是否是同一个View。
2.3 自定义Key
下面举个例子来说明Key与View的关系,由于Key与View要一一对应,所以我把每个视图所处的位置Position作为Key,在上章例子的基础上更改的,下面先看全部代码,然后看部分讲解:
import java.util.ArrayList;
import java.util.List;
import android.app.Activity;
import android.os.Bundle;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class MainActivity extends Activity {
private View view1, view2, view3;
private List<View> viewList;// view数组
private ViewPager viewPager; // 对应的viewPager
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
viewPager = (ViewPager) findViewById(R.id.viewpager);
LayoutInflater inflater = getLayoutInflater();
view1 = inflater.inflate(R.layout.layout1, null);
view2 = inflater.inflate(R.layout.layout2, null);
view3 = inflater.inflate(R.layout.layout3, null);
viewList = new ArrayList<View>();// 将要分页显示的View装入数组中
viewList.add(view1);
viewList.add(view2);
viewList.add(view3);
PagerAdapter pagerAdapter = new PagerAdapter() {
@Override
public boolean isViewFromObject(View arg0, Object arg1) {
// TODO Auto-generated method stub
//根据传来的key,找到view,判断与传来的参数View arg0是不是同一个视图
return arg0 == viewList.get((int)Integer.parseInt(arg1.toString()));
}
@Override
public int getCount() {
// TODO Auto-generated method stub
return viewList.size();
}
@Override
public void destroyItem(ViewGroup container, int position,
Object object) {
// TODO Auto-generated method stub
container.removeView(viewList.get(position));
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
// TODO Auto-generated method stub
container.addView(viewList.get(position));
//把当前新增视图的位置(position)作为Key传过去
return position;
}
};
viewPager.setAdapter(pagerAdapter);
}
}
先看Key的产生的位置instantiateItem():
我们在上讲也讲了在这个函数中Key是作为返回值与当前装入Container中的视图对应起来的。所以在这里我们返回postion与container.addView(viewList.get(position));里的viewList.get(position)这个视图对应起来。
isViewFromObject ():
判断从instantiateItem()返回来的Key与当前的View是否能对应起来,我们知道从instantiateItem传过来的其实是position,所以我们要根据position找到View,然后跟参数中的View arg0判断。
但在真正操作时出现了问题,我们要先将obect对应转换为int类型:(int)Integer.parseInt(arg1.toString());然后再根据position找到对应的View;