前言:
在Android开发的世界里面,ViewPager在我们的APP中穿梭,我想只要有点Android开发经验的程序猿都知道ViewPager,也知道简单的使用方法。但我想ViewPager的源码估计大家都不怎么想去分析,其实我觉得当你从源码上真正分析过一个控件,那么不管它怎么变,你都能使用自如,并且就算在使用的过程中遇到一些问题,你都能应付得过来。我一直都想把自己在工作中分析过的那些控件源码记录下来,这也是自己的一个交代,毕竟好记性不如烂笔头,再者,在博客上把自己分析的过程记录下来也会加深自己的理解。苦于一直都很忙,没有时间进行。好了,废话不多说,开始我们的ViewPager的分析吧!
一、ViewPager简介
ViewPager 顾名思义,是负责翻页的一个 View。准确说是一个ViewGroup,包含多个 View 页,在手指横向滑动屏幕时,其负责对 View 进行切换。其源码在 android.support.v4下可以找到。有兴趣的可以下载来看看。
二、ViewPager的使用
1、在布局文件中添加
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v4.view.ViewPager
android:id="@+id/viewpager"
android:layout_width="match_parent"
android:layout_height="340dip"
android:layout_centerInParent="true" />
</RelativeLayout>
其中
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_view_pager_demo);
mViewPager = (ViewPager) findViewById(R.id.viewpager);
initViewList();
PagerAdapter pagerAdapter = new PagerAdapter() {
@Override
public boolean isViewFromObject(View arg0, Object arg1) {
// TODO Auto-generated method stub
return arg0 == arg1;
}
@Override
public int getCount() {
// TODO Auto-generated method stub
return mViewList.size();
}
@Override
public void destroyItem(ViewGroup container, int position,
Object object) {
// TODO Auto-generated method stub
container.removeView(mViewList.get(position));
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
// TODO Auto-generated method stub
container.addView(mViewList.get(position));
return mViewList.get(position);
}
};
mViewPager.setAdapter(pagerAdapter);
}
private void initViewList() {
LayoutInflater inflater;
inflater = (LayoutInflater) SimpleViewPagerDemoActivity.this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mViewList = new ArrayList<View>();
List<Integer> viewResList = new ArrayList<Integer>();
viewResList.add(R.drawable.img1);
viewResList.add(R.drawable.img2);
viewResList.add(R.drawable.img3);
viewResList.add(R.drawable.img4);
viewResList.add(R.drawable.img5);
for (int i = 0; i < viewResList.size(); i++) {
View view = inflater.inflate(R.layout.viewpager_adapter, null);
ImageView imageView = (ImageView) view.findViewById(R.id.view_page_img);
imageView.setImageResource(viewResList.get(i));
mViewList.add(view);
}
}
其中,ViewPager的每一页的视图布局文件如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ImageView
android:id="@+id/view_page_img"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="fitXY"
/>
</LinearLayout>
这样,一个ViewPager的基本用法就完成了 ,我们来总结一些ViewPager的使用过程。首先,可以看到ViewPager是android.support.v4下面的一个类,所以在需要滑动页面的地方添加ViewPager,然后在代码中获取这个ViewPager,为这个ViewPager设置一个适配器,适配器是用来填充ViewPager的页面的,ViewPager所有页面的生成,销毁等过程都需要通过适配器来完成,所以适配器在ViewPager中起着非常重要的作用,ViewPager的适配器必须得继承于PagerAdapter。接下来我们从源码的角度上来好好挖掘一下ViewPager到底是什么鬼。
三、分析PagerAdapter适配器
PagerAdapter 来进行和数据绑定以及生成最终的 View 页,ViewPager 是通过setAdapter()来建立与PagerAdapter的联系。这个联系是双面的,一方面,ViewPager会拥有PagerAdapter 对象,从而可以在需要的时候调用PagerAdapter的方法,比如,在生成一个ViewPager的页面时,就会调用PagerAdapter的instantiateItem方法;另一方面,ViewPager会在setAdapter()中调用PagerAdapter的registerDataSetObserver()方法,注册一个PagerObserver对象,从而在PagerAdapter有所需要时(如notifyDataSetChanged()),调用PagerObserver中的方法(如onChanged),因为PagerObserver是ViewPager的一个内部类,所以可以直接调用ViewPager的方法,从而实现了PagerAdapter向ViewPager方向发送信息。
PagerAdapter的方法接口:
(1)public abstract int getCount(); 返回viewPager页面的数量
(2)public abstract boolean isViewFromObject(View view, Object object); 判断instantiateItem(ViewGroup, int)函数所返回来的Key与一个页面视图是否是代表的同一个视图(即它俩是否是对应的)
(3)public Object instantiateItem(ViewGroup container, int position) 创建指定位置的页面视图
(5)public void destroyItem(ViewGroup container, int position, Object object)移除指定位置的页面视图
(6)public void startUpdate(ViewGroup container)当显示的页面视图发生改变之前,将会回调这个方法
(7)public void finishUpdate(ViewGroup container)当 显示的页面视图发生即将改变之前,将会回调这个方法,它与startUpdate的区别是在startUpdate与finishUpdate之间会调用 若干次instantiateItem和destroyItem方法,也就是说,在调用finishUpdate的时候更新页面视图的准备工作已经做好 了,准备添加 进来的页面视图通过instantiateItem方法添加到了ViewPager中,不需要的页面视图通过destroyItem方法从 ViewPager中移除;而 startUpdate调用的时候,这些准备工作都没有开始。
(8)public void notifyDataSetChanged()通知ViewPager构造页面视图的数据发生了改变,需要刷新视图页面
(9)public int getItemPosition(Object object)当视图的数据发生改变时,判断视图页面是否需要创建
(10)public CharSequence getPageTitle(int position)设置指定位置的页面视图的标题
(11)public float getPageWidth(int position)指定指定位置的页面视图的宽度(0-1.0f,相对于ViewPager的宽度)
(12)public void unregisterDataSetObserver(DataSetObserver observer)移除ViewPager的观察者
(13)public void registerDataSetObserver(DataSetObserver observer)注册ViewPager的观察者
(14)public Parcelable saveState()保存与adapter关联的所有的页面,直到调用restoreState方法时被恢复
注意:
PagerAdapter是一个抽象类,当要实现一个PagerAdapter时,必须覆盖以下几个方法:
(1) instantiateItem(ViewGroup, int)
(2)destroyItem(ViewGroup, int, Object)
(3)getCount()
(4)isViewFromObject(View, Object)
这四个方法的具体含义是什么呢,接下来我们来揭示其真面目:
1、getCount ()
/**
* Return the number of views available.
*/
public abstract int getCount();
功能:设置viewpager的有效视图个数
返回值:viewpager有效视图的个数,即你想为viewpager设置的页数
2、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 from
* {@link #finishUpdate(ViewGroup)}.
*
* @param container The containing View in which the page will be shown.
* @param position The page position to be instantiated.
* @return Returns an Object representing the new page. This does not
* need to be a View, but can be some other container of the page.
*/
public Object instantiateItem(ViewGroup container, int position) {
return instantiateItem((View) container, position);
}
功能:创建指定位置的页面视图。也就是说viewpager的所有页面视图都需要在这个函数中添加到viewpager中。适配器有责任增加即将创建的View视图到这里给定的container中。
返回值:返回一个代表新增视图页面的Object(Key),这里没必要非要返回视图本身,只要你可以与你增加的View一一对应即可,比如position变量也可以做为Key
3、isViewFromObject (View view, Object object)
/**
* Determines whether a page View is associated with a specific key object
* as returned by {@link #instantiateItem(ViewGroup, int)}. This method is
* required for a PagerAdapter to function properly.
*
* @param view Page View to check for association with <code>object</code>
* @param object Object to check for association with <code>view</code>
* @return true if <code>view</code> is associated with the key object <code>object</code>
*/
public abstract boolean isViewFromObject(View view, Object object);
功能:该函数用来判断instantiateItem(ViewGroup, int)函数所返回来的Key与一个页面视图是否是代表的同一个视图(即它俩是否是对应的,对应的表示同一个View)
返回值:如果对应的是同一个View,返回True,否则返回False
4、destroyItem()
/**
* Remove a page for the given position. The adapter is responsible
* for removing the view from its container, although it only must ensure
* this is done by the time it returns from {@link #finishUpdate(ViewGroup)}.
*
* @param container The containing View from which the page will be removed.
* @param position The page position to be removed.
* @param object The same object that was returned by
* {@link #instantiateItem(View, int)}.
*/
public void destroyItem(ViewGroup container, int position, Object object) {
destroyItem((View) container, position, object);
}
功能:从viewpager移除指定位置的页面视图
返回值:无
四、PagerTitleStrip指示器
PagerTabStrip是ViewPager的一个关于当前页面、上一个页面和下一个页面的一个非交互的指示器。它经常作为ViewPager控件的一个子控件被被添加在XML布局文件中。在你的布局文件中,将它作为子控件添加在ViewPager中。而且要将它的 android:layout_gravity 属性设置为TOP或BOTTOM来将它显示在ViewPager的顶部或底部。每个页面的标题是通过适配器的getPageTitle(int)函数提供给ViewPager的。
1、布局文件中
<android.support.v4.view.ViewPager
android:id="@+id/viewpager"
android:layout_width="match_parent"
android:layout_height="340dip"
android:layout_centerInParent="true">
<android.support.v4.view.PagerTitleStrip
android:id="@+id/pagertitle"
android:layout_width="match_parent"
android:layout_height="50dip"
android:layout_gravity="top"
/>
</android.support.v4.view.ViewPager>
2、在代码中
List<String> mTitleList;
protected void onCreate(Bundle savedInstanceState) {
mTitleList = new ArrayList<String>();
mTitleList.add("Title1");
mTitleList.add("Title2");
mTitleList.add("Title3");
mTitleList.add("Title4");
mTitleList.add("Title5");
mPagerAdapter = new PagerAdapter() {
@Override
public CharSequence getPageTitle(int position) {
return mTitleList.get(position);
}
};
mViewPager.setAdapter(mPagerAdapter);
}
可以看到,PagerTabStrip的用法非常简单,只需要将PagerTitleStrip当作ViewPager的一个子控件添加到布局文件中,然后重写ViewPager的PagerAdpater的getPageTitle方法,设置指定页面的title即可。
本文详细介绍了Android中的ViewPager组件,包括基本使用方法、PagerAdapter适配器的工作原理及其核心方法解析,并介绍了PagerTitleStrip指示器的使用。
7337

被折叠的 条评论
为什么被折叠?



