您的位置:首页 > 移动开发 > Android开发

Android开发之ViewPager使用详解(一)

2015-11-30 09:27 609 查看
ViewPager在开发中用的还是比较多的,比方说一些引导页,应用的主界面,最近也是用到了好多次,于是就系统的学习了下,那么今天就来和大家一起来分享下ViewPager的用法,如有谬误欢迎批评指正,如有疑问欢迎留言。

通过本篇博客你将学到以下知识点:
①ViewPager的用法
②PagerAdapter的四个函数的用法(详细)

1、ViewPager的用法介绍

首先我们来看看ViewPager是什么东西?看看它的继承关系图



从继承图中我们可以看到它是继承自ViewGroup的,是一个容器,那么它应该怎么用呢?首先来引用官方文档的一段话:
布局管理器允许用户左右翻转页面的数据,你可以提供一个PagerAdapter来生成要显示的视图,ViewPager经常和Fragment一起使用,这样就可以很方便的提供和管理每一个界面的生命周期,有标准的适配器的实现方式用于使用Fragment的ViewPager,这样的适配器包含了最常见的案例,它就是FragmentPagerAdapter和FragmentStatePagerAdapter,这两个适配器都是简单的代码来演示如何构建一个完整的用户界面。

从官方给我们的介绍可以看出要想使用ViewPager首先要做的就是得给它一个适配器(这点跟ListView类似),它经常和Fragment一起使用(这个用法后面文正再讲),首先来学习PagerAdapter的用法,这也是今天的重点。
跟ViewPager一样首先来看看它的继承关系图



从图中看出PagerAdapter是support.v4下的一个类,它的直接子类有FragmentPagerAdapter和FragmentStatePagerAdapter。首先我们需要知道的是在继承PagerAdapter时必须要实现它的四个函数(这一点官方文档,以及方法的说明都可以看到),我在这里截个图给大家看一下



看到了吧,上面红框内的四个函数就是必须要重写的函数,那么它是怎么运作呢?再来看官方文档的一段关于PagerAdapter话:

第一段话的翻译

ViewPager将每一个页面与一个Key对象进行关联,而不是直接操作这个视图,这个Key对象用来跟踪和唯一的标识一个给定的视图,独立于适配器中的位置,调用PagerAdapter的startUpdate(ViewGroup)方法表明ViewPager的内容将要发生变化,接着一次或多次的调用instantiateItem(ViewGroup,int)和destroyItem(ViewGroup,int,Object)方法,通过调用finishUpdate(ViewGroup)来标识更新的完成,finishUpdate方法返回一个视图,这个视图和一个Key对象相关联,这个Key对象是instantiateItem的返回值,这个视图应该添加到父ViewGroup,传递给这些方法并且这个和Key相关的的视图会传递到destroyItem方法中,在这个方法中会将这个视图移除。方法isViewFromObject(View,Object)用于标识一个视图是否和给定的Key对象相关。

一个简单的PagerAdapter可以选择用视图本身做为Key对象,在视图创建并加入到父ViewGroup后通过instantiateItem(ViewGroup,int)方法将此视图返回。在destroyItem(ViewGroup,int,Object)这个方法中将会从父ViewGroup中将这个视图删除,而isViewFromObject(View,Object)可以这样实现:return view==object。

哎呦,我以后要努力学英语了。。。。

2、详解PagerAdapter的四大函数

从谷歌官方给出的文档中,可以看到ViewPager并不是直接操作每一个视图的本身,而是将各个视图与一个Key对象关联起来(这有点类似于Map),这个Key对象就和这个视图一一对应,并且这个Key对象就是instatiateItem(ViewGroup,int)这个方法的返回值。在最后谷歌给了我们建议,它建议我们将视图本身作为返回值,然后在isViewFromObject(View,Object)中直接 retutn view==object;看到这里肯定会有好多人云里雾里,这里稍微难理解一点的就是这个Key,不要着急我将通过一个小例子来专门讲解这个Key,还废什么话,接着我们通过两个实例来详细讲解PagerAdapter的用法,相信你看完后会理解PagerAdapter的用法,这个例子很简单,就是将几张图片添加到界面,这些界面可以左右滑动,效果图如下



首先来看下这里的PagerAdapter是怎么写的

package com.example.viewpagertest.adapter;

import java.util.List;

import android.content.Context;
import android.support.v4.view.PagerAdapter;
import android.view.View;
import android.view.ViewGroup;

public class MyAdapter extends PagerAdapter {
     
     private Context mContext;
     private List<View> mViewList;
     
     public MyAdapter(Context context, List<View> viewList){
            this. mContext=context;
            this. mViewList=viewList;
     }

     @Override
     public Object instantiateItem(ViewGroup container, int position) {

           container.addView( mViewList.get(position));
            return mViewList.get(position);
     }

     @Override
     public void destroyItem(ViewGroup container, int position, Object object) {
           
           container.removeView( mViewList.get(position));
     }

     @Override
     public int getCount() {
            return mViewList.size();
     }

     @Override
     public boolean isViewFromObject(View view, Object object) {
            //当返回为true的时候,就将根据当前的position得到的view展示出来
            return view== object;
     }
}


对PagerAdapter的这四个函数我将比对着谷歌文档来进行讲解

2.1 getCount方法

getCount方法的官方文档说明

返回视图的个数,这个方法很简单没什么可说的,在上面的例子中我们是这样做的

@Override
     public int getCount() {
            return mViewList.size();
     }
即将存放View的一个集合的大小返回,这里的大小也就是视图的个数

2.2 instantiateItem方法

instantiateItem方法的官方文档说明

这个方法的主要作用就是根据当前的posistion来创建对应的视图,并且将这个创建好的视图添加到容器中,这个添加操作是在调用
finishUpdate(ViewGroup)这个方法之前完成的。
instantiateItem 方法会返回一个对象,这个对象代表这一个新的视图,这个对象不一定是一个View,可以是这个视图的其他容器,也就是说只要可以唯一代表这个界面的东西都可以作为这个对象。
在上述例子中我们是这样实现的
@Override
      public Object instantiateItem(ViewGroup container, int position) {

           container.addView( mViewList.get(position));
            return mViewList.get(position);
     }
将mViewList中的一个View取出来,添加到视图中,然后将这个视图返回,这里也是按照谷歌的建议来写的。此时这个return的mViewList.get(position)就和这个添加到containter的View对应了起来。

2.3 isViewFromObject方法

这个方法的作用就是用来判断
instantiateItem(ViewGroup,
 int)方法返回的Key是否和界面的View相关联,如果关联则返回true,否则返回false。关于返回true和返回false的区别谷歌官方文档没有说明,看了好多资料最后在stackoverflow上找到了答案,这里把这个链接的地址贴出来:
http://stackoverflow.com/questions/30995446/what-is-the-role-of-isviewfromobject-view-view-object-object-in-fragmentst
当返回为true时就将根据当前的position得到的view展示出来,否则就不展示。这里可以直接返回false发现viewpager一个界面也没有,直接返回true可以看到重合的界面,大家去自己去试试。
在上面的例子中我们是这么写的
@Override
     public boolean isViewFromObject(View view, Object object) {
            //当返回为true的时候,就将根据当前的position得到的view展示出来
            return view==object;
     }
这也是谷歌建议的方式,这里的view就是当前要展示的界面,这里的object就是instantiateItem方法的返回值,因为在instantiateItem方法中返回了这个界面所以这里view==object是为true的。

2.4 destroyItem方法

这个方法的作用就是从容器中移除position所对应的视图,而且这个移除的动作是在finishUpdate之前完成的。这个在 instantiateItem 方法中也提到过,也就是说在finishUpdate之前至少要完成两个动作①原来视图的移除②新视图的增加
在上面的例子我们是这么做的
@Override
     public void destroyItem(ViewGroup container, int position, Object object) {
           
           container.removeView( mViewList.get(position));
     }
即根据position移除它所对应的界面。

到这里PagerAdapter的四个方法就介绍完了,看完后大家可能对Key这个概念有点模糊,没关系,接下来我们不按照谷歌给我们的建议即不将View本身作为instantiateItem方法的返回值。

3、深入理解Key的两个案例
从instantiateItem的方法介绍能够看到能够作为Key不仅仅是View本身也可以是其它的。那么我们就来两个自定义的Key的例子,这两个例子也非常简单就是对上面的代码做简单的修改,其它的内容不变只修改PagerAdapter的内容。

案例一

对上述例子中的MyAdapter修改后的代码如下

package com.example.viewpagertest.adapter;

import java.util.List;

import android.content.Context;
import android.support.v4.view.PagerAdapter;
import android.view.View;
import android.view.ViewGroup;

public class MyAdapter extends PagerAdapter {

private Context mContext;
private List<View> mViewList;

public MyAdapter(Context context, List<View> viewList){
this. mContext=context;
this. mViewList=viewList;
}

@Override
public Object instantiateItem(ViewGroup container, int position) {

container.addView( mViewList.get(position));
return position;
}

@Override public void destroyItem(ViewGroup container, int position, Object object) { container.removeView( mViewList.get(position)); }
@Override public int getCount() { return mViewList.size(); }
@Override
public boolean isViewFromObject(View view, Object object) {
//当返回为true的时候,就将根据当前的position得到的view展示出来
return view==mViewList.get(Integer.parseInt(object.toString()));
}
}
这里只是将instantiateItem方法的返回值由mViewList.get(position)变成了position,然后将isViewFromObject方法的返回值由view== object改为了view==mViewList .get(Integer.parseInt(object.toString())),然后运行程序你会发现和之前的效果一样,这里的instantiateItem方法将position返回然后在isViewFromObject方法中根据这个position找到View然后判断是否相等,从而决定这个position的View是否展示出来。

案例二
package com.example.viewpagertest.adapter;

import java.util.ArrayList;
import java.util.List;

import com.example.viewpagertest.R;

import android.content.Context;
import android.support.v4.view.PagerAdapter;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;

public class MyAdapter extends PagerAdapter {

private Context mContext;
private List<View> mViewList;
private List<Integer> mList;

public MyAdapter(Context context, List<View> viewList){
this. mContext=context;
this. mViewList=viewList;

mList= new ArrayList<Integer>();
}

@Override
public Object instantiateItem(ViewGroup container, int position) {

View view = mViewList.get(position);
container.addView(view);

ImageView iv = (ImageView) view.findViewById(R.id.iv_test );

return iv;
}

@Override public void destroyItem(ViewGroup container, int position, Object object) { container.removeView( mViewList.get(position)); }
@Override public int getCount() { return mViewList.size(); }
@Override
public boolean isViewFromObject(View view, Object object) {
//当返回为true的时候,就将根据当前的position得到的view展示出来
ImageView iv =(ImageView) view.findViewById(R.id.iv_test );

return iv==object;
}
}


这次我们也是做了两处修改,这里在instantiateItem这个方法中返回当前View中的ImageView对象,让ImageView对象作为标志这个界面的Key,而在isViewFromObject这个方法中通过view查找出ImageView然后判断这两个ImageView是不是同一个View中的ImageView如果是就显示,否则不显示。到这里相信大家对Key这个概念应该有了清楚的认识。

好了,到这里关于ViewPager的pagerAdapter的用法就介绍完了,后面会继续给大家带来FragmentPagerAdapter等,关于ViewPager的知识,不知道大家还有没有什么疑问,如果大家发现本文中有错误,或者有什么疑问欢迎批评指正,大家共同进步,谢谢。。。

如果你觉着本文对你有帮助我绝对不介意你顶一下,赞一个,哈哈。。。。

博客中源码点这里
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: