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

   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的知识,不知道大家还有没有什么疑问,如果大家发现本文中有错误,或者有什么疑问欢迎批评指正,大家共同进步,谢谢。。。

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

博客中源码点这里







  • 9
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
使用 ViewPager 实现轮播图,需要遵循以下几个步骤: 1.在布局文件中添加 ViewPager 组件和指示器组件(如小圆点)。 ```xml <androidx.viewpager.widget.ViewPager android:id="@+id/viewPager" android:layout_width="match_parent" android:layout_height="200dp"/> <LinearLayout android:id="@+id/indicatorLayout" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:gravity="center"/> ``` 2.创建适配器类,继承自 ViewPager.Adapter,并实现 getCount()、instantiateItem()、destroyItem()、isViewFromObject() 等方法。 ```java public class ViewPagerAdapter extends PagerAdapter { private Context mContext; private int[] mImageIds; public ViewPagerAdapter(Context context, int[] imageIds) { mContext = context; mImageIds = imageIds; } @Override public int getCount() { return mImageIds.length; } @Override public Object instantiateItem(ViewGroup container, int position) { ImageView imageView = new ImageView(mContext); imageView.setScaleType(ImageView.ScaleType.CENTER_CROP); imageView.setImageResource(mImageIds[position]); container.addView(imageView); return imageView; } @Override public void destroyItem(ViewGroup container, int position, Object object) { container.removeView((ImageView) object); } @Override public boolean isViewFromObject(View view, Object object) { return view == object; } } ``` 3.在 Activity 或 Fragment 中设置 ViewPager 的适配器,并为其添加一个 OnPageChangeListener 监听器,用于实现指示器的更新。 ```java ViewPager viewPager = findViewById(R.id.viewPager); int[] imageIds = {R.drawable.image1, R.drawable.image2, R.drawable.image3}; ViewPagerAdapter adapter = new ViewPagerAdapter(this, imageIds); viewPager.setAdapter(adapter); LinearLayout indicatorLayout = findViewById(R.id.indicatorLayout); for (int i = 0; i < imageIds.length; i++) { ImageView imageView = new ImageView(this); imageView.setImageResource(R.drawable.indicator_normal); indicatorLayout.addView(imageView); } final int indicatorCount = indicatorLayout.getChildCount(); viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { } @Override public void onPageSelected(int position) { for (int i = 0; i < indicatorCount; i++) { ImageView imageView = (ImageView) indicatorLayout.getChildAt(i); if (i == position) { imageView.setImageResource(R.drawable.indicator_selected); } else { imageView.setImageResource(R.drawable.indicator_normal); } } } @Override public void onPageScrollStateChanged(int state) { } }); ``` 这样就可以实现一个基本的 ViewPager 轮播图,并在指示器中显示当前码。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值