Android App开发中ViewPager组件的入门使用教程

时间:2022-12-05 12:34:54

首先让大家有个全局的认识,直接上个项目,看看仅仅通过这几行代码,竟然就能完成如此强悍的功能。下篇再仔细讲讲为什么要这么写。
效果图:
实现了三个view间的相互滑动
第一个view向第二个view滑动:

Android App开发中ViewPager组件的入门使用教程

第二个view向第三个view滑动:

Android App开发中ViewPager组件的入门使用教程

一、新建项目,引入viewpager控件
viewpager。它是google sdk中自带的一个附加包的一个类,可以用来实现屏幕间的切换。

1.在主布局文件里加入

?
1
2
3
4
5
6
7
8
9
10
11
12
13
<relativelayout xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:tools="http://schemas.android.com/tools"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
  tools:context="com.example.testviewpage_1.mainactivity" >
 
<android.support.v4.view.viewpager
  android:id="@+id/viewpager"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:layout_gravity="center" />
 
</relativelayout>

其中 <android.support.v4.view.viewpager /> 是viewpager对应的组件,要将其放到想要滑动的位置

2、新建三个layout,用于滑动切换的视图
从效果图中也可以看到,我们的三个视图都非常简单,里面没有任何的控件,大家当然可以往里添加各种控件,但这里是个demo,只详解原理即可,所以我这里仅仅用背景来区别不用layout布局。

布局代码分别如下:

layout1.xml

?
1
2
3
4
5
6
7
8
9
<?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:background="#ffffff"
  android:orientation="vertical" >
   
 
</linearlayout>

layout2.xml

?
1
2
3
4
5
6
7
8
9
<?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:background="#ffff00"
  android:orientation="vertical" >
   
 
</linearlayout>

layout3.xml

?
1
2
3
4
5
6
7
8
9
10
<?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:background="#ff00ff"
  android:orientation="vertical" >
   
 
</linearlayout><span style="color:#660000;">
</span>

二、代码实战
先上整体代码,然后逐步讲解。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
package com.example.testviewpage_1;
 
import java.util.arraylist;
import java.util.list;
import java.util.zip.inflater;
 
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 viewpager viewpager; //对应的viewpager
   
  private list<view> viewlist;//view数组
   
   
  @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
        return arg0 == arg1;
      }
       
      @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));
         
         
        return viewlist.get(position);
      }
    };
     
     
    viewpager.setadapter(pageradapter);
     
  }
 
 
}

代码量很小,全部放在了oncreate()函数中。
1、先看声明的变量的意义:

?
1
2
3
private view view1, view2, view3;
private list<view> viewlist;//view数组
private viewpager viewpager; //对应的viewpager

首先viewpager对应 <android.support.v4.view.viewpager/>控件。

view1,view2 ,view3对应我们的三个layout,即layout1.xml,layout2.xml,layout3.xml
viewlist是一个view数组,盛装上面的三个view

2、接下来是他们的初始化过程:

?
1
2
3
4
5
6
7
8
9
10
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);

初始化过程难度不大,就是将资源与变量联系起来布局,最后将实例化的view1,view2,view3添加到viewlist中
3、pageadapter——pageview的适配器
适配器这个东东想必大家都不莫生,在listview中也有适配器,listview通过重写getview()函数来获取当前要加载的item。而pageadapter不太相同,毕竟pageadapter是单个view的合集。

pageadapter 必须重写的四个函数:

(1)boolean isviewfromobject(view arg0, object arg1)
(2)int getcount()
(3)void destroyitem(viewgroup container, int position,object object)
(4)object instantiateitem(viewgroup container, int position)
先看看各个函数,我们上面都做了什么吧:

?
1
2
3
4
5
@override
public int getcount() {
  // todo auto-generated method stub
  return viewlist.size();
}

getcount():返回要滑动的view的个数

?
1
2
3
4
5
6
@override
public void destroyitem(viewgroup container, int position,
    object object) {
  // todo auto-generated method stub
  container.removeview(viewlist.get(position));
}

destroyitem():从当前container中删除指定位置(position)的view;

?
1
2
3
4
5
6
7
8
9
@override
public object instantiateitem(viewgroup container, int position) {
  // todo auto-generated method stub
    container.addview(viewlist.get(position));
     
     
    return viewlist.get(position);
  }
};

instantiateitem():做了两件事,第一:将当前视图添加到container中,第二:返回当前view

?
1
2
3
4
5
@override
public boolean isviewfromobject(view arg0, object arg1) {
  // todo auto-generated method stub
  return arg0 == arg1;
}

isviewfromobject():对于这个函数就先不做讲解,大家目前先知道它要这样重写就行了,后面我们会对它进行改写。 

三、对键key的理解
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。
经过上面的讲解和实战例子,想必大家给key的概念应该有个清楚的理解,下面举个例子来说明key与view的关系,由于key与view要一一对应,所以我把每个视图所处的位置position作为key,在上章例子的基础上更改的,下面先看全部代码,然后看部分讲解:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
package com.example.testviewpage_2;
/**
 * @author harvic
 * @date 2014.8.11
 */
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);
 
  }
 
}

在这里更改了两个地方:
1、先看key的产生的位置instantiateitem()

?
1
2
3
4
5
6
7
8
@override
public object instantiateitem(viewgroup container, int position) {
  // todo auto-generated method stub
  container.addview(viewlist.get(position));
 
  //把当前新增视图的位置(position)作为key传过去
  return position;
}

在这个函数中key是作为返回值与当前装入container中的视图对应起来的。所以在这里我们返回postion与container.addview(viewlist.get(position));里的viewlist.get(position)这个视图对应起来。
2、isviewfromobject ()

?
1
2
3
4
5
6
@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()));
}

判断从instantiateitem()返回来的key与当前的view是否能对应起来,我们知道从instantiateitem传过来的其实是position,所以我们要根据position找到view,然后跟参数中的view arg0判断。

但在真正操作时出现了问题,我们要先将obect对应转换为int类型:(int)integer.parseint(arg1.tostring());然后再根据position找到对应的view;

效果图:三个view之间的滑动切换

Android App开发中ViewPager组件的入门使用教程Android App开发中ViewPager组件的入门使用教程