ViewPager原理分析

本文详细介绍了Android中的ViewPager组件,包括基本使用方法、PagerAdapter适配器的工作原理及其核心方法解析,并介绍了PagerTitleStrip指示器的使用。

前言:
在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即可。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值