ViewPager 详解


目录(?)[+]

前言:这两天研究研究ViewPager滚动功能,现在很多的app都有用到这个功能,我们的大虾米也有这个模块。要研究就彻底的研究研究,我从不满足于一个功能只是简单的应用,要学就学的彻底,所以我打算将ViewPager 分几篇写,研究的哪个程度就写到哪个程度吧。今天是第一篇,基本入门篇 。


相关文章:

1、《ViewPager 详解(一)---基本入门》

2、《ViewPager 详解(二)---详解四大函数》

3、《ViewPager 详解(三)---PagerTabStrip与PagerTitleStrip添加标题栏的异同》

4、《ViewPager 详解(四)----自主实现滑动指示条》

5、《ViewPager 详解(五)-----使用Fragment实现ViewPager滑动》


首先让大家有个全局的认识,直接上个项目,看看仅仅通过这几行代码,竟然就能完成如此强悍的功能。下篇再结合API仔细讲讲为什么要这么写。

效果图:

实现了三个view间的相互滑动

                     第一个VIEW向第二个VIEW滑动       第二个VIEW向第三个VIEW滑动

   

一、新建项目,引入ViewPager控件

ViewPager。它是google SDk中自带的一个附加包的一个类,可以用来实现屏幕间的切换。

1.在主布局文件里加入

[html]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  2.     xmlns:tools="http://schemas.android.com/tools"  
  3.     android:layout_width="fill_parent"  
  4.     android:layout_height="fill_parent"  
  5.     tools:context="com.example.testviewpage_1.MainActivity" >  
  6.   
  7. <android.support.v4.view.ViewPager  
  8.     android:id="@+id/viewpager"  
  9.     android:layout_width="wrap_content"  
  10.     android:layout_height="wrap_content"  
  11.     android:layout_gravity="center" />  
  12.   
  13. </RelativeLayout>  

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

2、新建三个layout,用于滑动切换的视图

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

布局代码分别如下:

layout1.xml

[html]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:layout_width="match_parent"  
  4.     android:layout_height="match_parent"  
  5.     android:background="#ffffff"  
  6.     android:orientation="vertical" >  
  7.       
  8.   
  9. </LinearLayout>  
layout2.xml

[html]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:layout_width="match_parent"  
  4.     android:layout_height="match_parent"  
  5.     android:background="#ffff00"  
  6.     android:orientation="vertical" >  
  7.       
  8.   
  9. </LinearLayout>  
layout3.xml
[html]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:layout_width="match_parent"  
  4.     android:layout_height="match_parent"  
  5.     android:background="#ff00ff"  
  6.     android:orientation="vertical" >  
  7.       
  8.   
  9. </LinearLayout><span style="color:#660000;">  
  10. </span>  

二、代码实战

先上整体代码,然后逐步讲解。
[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. package com.example.testviewpage_1;  
  2. /** 
  3.  * @author  harvic 
  4.  * @date 2014.8.9 
  5.  */  
  6. import java.util.ArrayList;  
  7. import java.util.List;  
  8. import java.util.zip.Inflater;  
  9.   
  10. import android.app.Activity;  
  11. import android.os.Bundle;  
  12. import android.support.v4.view.PagerAdapter;  
  13. import android.support.v4.view.ViewPager;  
  14. import android.view.LayoutInflater;  
  15. import android.view.View;  
  16. import android.view.ViewGroup;  
  17.   
  18.   
  19. public class MainActivity extends Activity {  
  20.   
  21.     private View view1, view2, view3;  
  22.     private ViewPager viewPager;  //对应的viewPager  
  23.       
  24.     private List<View> viewList;//view数组  
  25.      
  26.      
  27.     @Override  
  28.     protected void onCreate(Bundle savedInstanceState) {  
  29.         super.onCreate(savedInstanceState);  
  30.         setContentView(R.layout.activity_main);  
  31.           
  32.         viewPager = (ViewPager) findViewById(R.id.viewpager);  
  33.         LayoutInflater inflater=getLayoutInflater();  
  34.         view1 = inflater.inflate(R.layout.layout1, null);  
  35.         view2 = inflater.inflate(R.layout.layout2,null);  
  36.         view3 = inflater.inflate(R.layout.layout3, null);  
  37.           
  38.         viewList = new ArrayList<View>();// 将要分页显示的View装入数组中  
  39.         viewList.add(view1);  
  40.         viewList.add(view2);  
  41.         viewList.add(view3);  
  42.           
  43.           
  44.         PagerAdapter pagerAdapter = new PagerAdapter() {  
  45.               
  46.             @Override  
  47.             public boolean isViewFromObject(View arg0, Object arg1) {  
  48.                 // TODO Auto-generated method stub  
  49.                 return arg0 == arg1;  
  50.             }  
  51.               
  52.             @Override  
  53.             public int getCount() {  
  54.                 // TODO Auto-generated method stub  
  55.                 return viewList.size();  
  56.             }  
  57.               
  58.             @Override  
  59.             public void destroyItem(ViewGroup container, int position,  
  60.                     Object object) {  
  61.                 // TODO Auto-generated method stub  
  62.                 container.removeView(viewList.get(position));  
  63.             }  
  64.               
  65.             @Override  
  66.             public Object instantiateItem(ViewGroup container, int position) {  
  67.                 // TODO Auto-generated method stub  
  68.                 container.addView(viewList.get(position));  
  69.                   
  70.                   
  71.                 return viewList.get(position);  
  72.             }  
  73.         };  
  74.           
  75.           
  76.         viewPager.setAdapter(pagerAdapter);  
  77.           
  78.     }  
  79.   
  80.   
  81. }  
代码量很小,全部放在了OnCreate()函数中。

1、先看声明的变量的意义:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. private View view1, view2, view3;  
  2. private List<View> viewList;//view数组  
  3. private ViewPager viewPager;  //对应的viewPager  

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

view1,view2 ,view3对应我们的三个layout,即layout1.xml,layout2.xml,layout3.xml

viewList是一个View数组,盛装上面的三个VIEW

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

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. viewPager = (ViewPager) findViewById(R.id.viewpager);  
  2. LayoutInflater inflater=getLayoutInflater();  
  3. view1 = inflater.inflate(R.layout.layout1, null);  
  4. view2 = inflater.inflate(R.layout.layout2,null);  
  5. view3 = inflater.inflate(R.layout.layout3, null);  
  6.   
  7. viewList = new ArrayList<View>();// 将要分页显示的View装入数组中  
  8. viewList.add(view1);  
  9. viewList.add(view2);  
  10. viewList.add(view3);  
初始化过程难度不大,就是将资源与变量联系起来布局,最后将实例化的view1,view2,view3添加到viewList中

3、PageAdapter——PageView的适配器

适配器这个东东想必大家都不莫生,在ListView中也有适配器,listView通过重写GetView()函数来获取当前要加载的Item。而PageAdapter不太相同,毕竟PageAdapter是单个VIew的合集。

PageAdapter 必须重写的四个函数:

  • boolean isViewFromObject(View arg0, Object arg1)
  • int getCount() 
  • void destroyItem(ViewGroup container, int position,Object object)
  • Object instantiateItem(ViewGroup container, int position)

先看看各个函数,我们上面都做了什么吧:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. @Override  
  2. public int getCount() {  
  3.     // TODO Auto-generated method stub  
  4.     return viewList.size();  
  5. }  
getCount():返回要滑动的VIew的个数

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. @Override  
  2. public void destroyItem(ViewGroup container, int position,  
  3.         Object object) {  
  4.     // TODO Auto-generated method stub  
  5.     container.removeView(viewList.get(position));  
  6. }  
destroyItem():从当前container中删除指定位置(position)的View;
[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. @Override  
  2. public Object instantiateItem(ViewGroup container, int position) {  
  3.     // TODO Auto-generated method stub  
  4.         container.addView(viewList.get(position));  
  5.           
  6.           
  7.         return viewList.get(position);  
  8.     }  
  9. };  
instantiateItem():做了两件事,第一:将当前视图添加到container中,第二:返回当前View
[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. @Override  
  2. public boolean isViewFromObject(View arg0, Object arg1) {  
  3.     // TODO Auto-generated method stub  
  4.     return arg0 == arg1;  
  5. }  
isViewFromObject():对于这个函数就先不做讲解,大家目前先知道它要这样重写就行了,后面我们会对它进行改写。


下一篇,我将仔细讲解这几个函数的意义,与有关Key的知识,当然最后也会有个例子给大家。这篇就到这了。


前言:上篇中我们讲解了如何快速实现了一个滑动页面,但问题在于,PageAdapter必须要重写的四个函数,它们都各有什么意义,在上节的函数内部为什么要这么实现,下面我们就结合android的API说明,详细讲解一下。


相关文章:

1、《ViewPager 详解(一)---基本入门》

2、《ViewPager 详解(二)---详解四大函数》

3、《ViewPager 详解(三)---PagerTabStrip与PagerTitleStrip添加标题栏的异同》

4、《ViewPager 详解(四)----自主实现滑动指示条》

5、《ViewPager 详解(五)-----使用Fragment实现ViewPager滑动》


这篇涉及到内容比较多,因为有英文文档和中文文档,还有示例,在排版上很难驾驭(因为本人语文太烂……),所以排版有点非常的不赏心悦目,所以只能靠大家耐着性子慢慢看了……,我觉得大家看完之后应该会有所收获,谢谢。

一、SDK讲解

1、官方文档:(看不懂没关系,下面有翻译)

Class Overview


Base class providing the adapter to populate pages inside of a ViewPager. You will most likely want to use a more specific implementation of this, such as FragmentPagerAdapter orFragmentStatePagerAdapter.

When you implement a PagerAdapter, you must override the following methods at minimum:

PagerAdapter is more general than the adapters used for AdapterViews. Instead of providing a View recycling mechanism directly ViewPager uses callbacks to indicate the steps taken during an update. A PagerAdapter may implement a form of View recycling if desired or use a more sophisticated method of managing page Views such as Fragment transactions where each page is represented by its own Fragment.

ViewPager associates each page with a key Object instead of working with Views directly. This key is used to track and uniquely identify a given page independent of its position in the adapter. A call to the PagerAdapter method startUpdate(ViewGroup) indicates that the contents of the ViewPager are about to change. One or more calls to instantiateItem(ViewGroup, int) and/ordestroyItem(ViewGroup, int, Object) will follow, and the end of an update will be signaled by a call to finishUpdate(ViewGroup). By the time finishUpdate returns the views associated with the key objects returned by instantiateItem should be added to the parent ViewGroup passed to these methods and the views associated with the keys passed to destroyItem should be removed. The method isViewFromObject(View, Object) identifies whether a page View is associated with a given key object.

A very simple PagerAdapter may choose to use the page Views themselves as key objects, returning them from instantiateItem(ViewGroup, int) after creation and adding them to the parent ViewGroup. A matching destroyItem(ViewGroup, int, Object) implementation would remove the View from the parent ViewGroup and isViewFromObject(View, Object) could be implemented as return view == object;.

PagerAdapter supports data set changes. Data set changes must occur on the main thread and must end with a call to notifyDataSetChanged() similar to AdapterView adapters derived fromBaseAdapter. A data set change may involve pages being added, removed, or changing position. The ViewPager will keep the current page active provided the adapter implements the methodgetItemPosition(Object).

网址:http://developer.android.com/reference/android/support/v4/view/PagerAdapter.html

2、对应翻译

Class Overview


提供一个适配器用于填充ViewPager页面. 你很可能想要使用一个更加具体的实现, 例如: FragmentPagerAdapter or FragmentStatePagerAdapter.

当你实现一个PagerAdapter时,至少需要覆盖以下几个方法:

PagerAdapter比AdapterView的使用更加普通.ViewPager使用回调函数来表示一个更新的步骤,而不是使用一个视图回收机制。在需要的时候pageradapter也可以实现视图的回收或者使用一种更为巧妙的方法来管理视图,比如采用可以管理自身视图的fragment。

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。
 
pageradapter支持数据集合的改变,数据集合的改变必须要在主线程里面执行,然后还要调用notifyDataSetChanged方法。和baseadapter非常相似。数据集合的改变包括页面的添加删除和修改位置。viewpager要维持当前页面是活动的,所以你必须提供getItemPosition方法。

网址:http://www.cnblogs.com/tony-yang-flutter/p/3591825.html

3、解析

看上面的翻译,与我们相关只有这两段话:

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。

对于上面两段话,我这里有两点要着重讲一下:

1、第一段说明了,键(Key)的概念,首先这里要清楚的一点是,每个滑动页面都对应一个Key,而且这个Key值是用来唯一追踪这个页面的,也就是说每个滑动页面都与一个唯一的Key一一对应。大家先有这个概念就好,关于这个Key是怎么来的,下面再讲。

2、第二段简单讲了一个应用,即将当前页面本身的View作为Key。其实这个应用就是我们前一章讲的例子应用。不太理解?没关系,下面细讲。下面我们讲讲Key的问题

4、关于Key

现在我带着大家看看几个方法的官方文档:(这里结合《ViewPager 详解(一)---基本入门》最底部的例子来看)

首先:destroyItem()

public void destroyItem (ViewGroup container, int position, Object object)

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 fromfinishUpdate(ViewGroup).

Parameters
container The containing View from which the page will be removed.
position The page position to be removed.
object The same object that was returned by instantiateItem(View, int).

该方法实现的功能是移除一个给定位置的页面。适配器有责任从容器中删除这个视图。这是为了确保在finishUpdate(viewGroup)返回时视图能够被移除。

下面看看《ViewPager 详解(一)---基本入门》中是如何做的:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. @Override  
  2. public void destroyItem(ViewGroup container, int position,  
  3.         Object object) {  
  4.     // TODO Auto-generated method stub  
  5.     container.removeView(viewList.get(position));  
  6. }  
果不其然,我们将给定位置的视图从container中移除了……

然后看getCount ()

public abstract int getCount ()

Return the number of views available.

返回当前有效视图的个数。

在上一章例子中,我们是这么做的:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. @Override  
  2. public int getCount() {  
  3.     // TODO Auto-generated method stub  
  4.     return viewList.size();  
  5. }  
返回了当前要滑动视图的个数,与SDK说明一致。

最难的两个来了

instantiateItem (ViewGroup container, int position)

public Object 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 fromfinishUpdate(ViewGroup).

Parameters
container The containing View in which the page will be shown.
position The page position to be instantiated.
Returns
  • Returns an Object representing the new page. This does not need to be a View, but can be some other container of the page.
这个函数的实现的功能是创建指定位置的页面视图。适配器有责任增加即将创建的View视图到这里给定的container中,这是为了确保在finishUpdate(viewGroup)返回时this is be done!

返回值:返回一个代表新增视图页面的Object(Key),这里没必要非要返回视图本身,也可以这个页面的其它容器。其实我的理解是可以代表当前页面的任意值,只要你可以与你增加的View一一对应即可,比如position变量也可以做为Key(最后我们举个例子试试可不可行)

心得 :

1、从说明中可以看到,在代码中,我们的责任是将指定position的视图添加到conatiner中

2、Key的问题:从这个函数就可以看出,该函数返回值就是我们根据参数position增加到conatiner里的View的所对应的Key!!!!!!!

3、“it only must ensure this is done by the time it returns fromfinishUpdate(ViewGroup).”这句话在destroyItem()的函数说明中同样出现过,这说明在 finishUpdate(viewGroup)执行完后,有两个操作,一个是原视图的移除(不再显示的视图),另一个是新增显示视图(即将显示的视图)

在上一章的代码中,我们是这样做的:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. @Override  
  2. public Object instantiateItem(ViewGroup container, int position) {  
  3.     // TODO Auto-generated method stub  
  4.         container.addView(viewList.get(position));  
  5.           
  6.           
  7.         return viewList.get(position);  
  8.     }  
  9. };  
在这里,我们做了两件事

第一:将参数里给定的position的视图,增加到conatiner中,供其创建并显示、。

第二:返回当前position的View做为此视图的Key。还记得API官方文档中下面这段话么?
对于非常简单的pageradapter或许你可以选择用page本身作为键,在创建并且添加到viewgroup后instantiateItem方法里返回该page本身即可destroyItem将会将该page从viewgroup里面移除。isViewFromObject方法里面直接可以返回view == object。

这里就把当前的View当作Key传过出去!!!!

最后一个: isViewFromObject (View view, Object object)

public abstract boolean isViewFromObject (View view, Object object)

Determines whether a page View is associated with a specific key object as returned by instantiateItem(ViewGroup, int). This method is required for a PagerAdapter to function properly.

Parameters
view Page View to check for association with object
object Object to check for association with view
Returns
  • true if view is associated with the key object object
功能:该函数用来判断instantiateItem(ViewGroup, int)函数所返回来的Key与一个页面视图是否是代表的同一个视图(即它俩是否是对应的,对应的表示同一个View)

返回值:如果对应的是同一个View,返回True,否则返回False。

在上章节的例子中,我们这样做的:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. @Override  
  2. public boolean isViewFromObject(View arg0, Object arg1) {  
  3.     // TODO Auto-generated method stub  
  4.     return arg0 == arg1;  
  5. }  
由于在instantiateItem()中,我们作为Key返回来的是当前的View,所以在这里判断时,我们直接将Key与View看是否相等来判断是否是同一个View。

二、自定义Key实例

经过上面的讲解,想必大家给Key的概念应该有个清楚的理解,下面举个例子来说明Key与View的关系,由于Key与View要一一对应,所以我把每个视图所处的位置Position作为Key,在上章例子的基础上更改的,下面先看全部代码,然后看部分讲解:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. package com.example.testviewpage_2;  
  2. /** 
  3.  * @author  harvic 
  4.  * @date 2014.8.11 
  5.  */  
  6. import java.util.ArrayList;  
  7. import java.util.List;  
  8. import android.app.Activity;  
  9. import android.os.Bundle;  
  10. import android.support.v4.view.PagerAdapter;  
  11. import android.support.v4.view.ViewPager;  
  12. import android.view.LayoutInflater;  
  13. import android.view.View;  
  14. import android.view.ViewGroup;  
  15.   
  16. public class MainActivity extends Activity {  
  17.   
  18.     private View view1, view2, view3;  
  19.     private List<View> viewList;// view数组  
  20.     private ViewPager viewPager; // 对应的viewPager  
  21.       
  22.     @Override  
  23.     protected void onCreate(Bundle savedInstanceState) {  
  24.         super.onCreate(savedInstanceState);  
  25.         setContentView(R.layout.activity_main);  
  26.         viewPager = (ViewPager) findViewById(R.id.viewpager);  
  27.         LayoutInflater inflater = getLayoutInflater();  
  28.         view1 = inflater.inflate(R.layout.layout1, null);  
  29.         view2 = inflater.inflate(R.layout.layout2, null);  
  30.         view3 = inflater.inflate(R.layout.layout3, null);  
  31.   
  32.         viewList = new ArrayList<View>();// 将要分页显示的View装入数组中  
  33.         viewList.add(view1);  
  34.         viewList.add(view2);  
  35.         viewList.add(view3);  
  36.   
  37.         PagerAdapter pagerAdapter = new PagerAdapter() {  
  38.   
  39.             @Override  
  40.             public boolean isViewFromObject(View arg0, Object arg1) {  
  41.                 // TODO Auto-generated method stub  
  42.                 //根据传来的key,找到view,判断与传来的参数View arg0是不是同一个视图  
  43.                 return arg0 == viewList.get((int)Integer.parseInt(arg1.toString()));  
  44.             }  
  45.   
  46.             @Override  
  47.             public int getCount() {  
  48.                 // TODO Auto-generated method stub  
  49.                 return viewList.size();  
  50.             }  
  51.   
  52.             @Override  
  53.             public void destroyItem(ViewGroup container, int position,  
  54.                     Object object) {  
  55.                 // TODO Auto-generated method stub  
  56.                 container.removeView(viewList.get(position));  
  57.             }  
  58.   
  59.             @Override  
  60.             public Object instantiateItem(ViewGroup container, int position) {  
  61.                 // TODO Auto-generated method stub  
  62.                 container.addView(viewList.get(position));  
  63.   
  64.                 //把当前新增视图的位置(position)作为Key传过去  
  65.                 return position;  
  66.             }  
  67.         };  
  68.   
  69.         viewPager.setAdapter(pagerAdapter);  
  70.   
  71.     }  
  72.   
  73. }  
在这里更改了两个地方:

1、先看Key的产生的位置instantiateItem()

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. @Override  
  2. public Object instantiateItem(ViewGroup container, int position) {  
  3.     // TODO Auto-generated method stub  
  4.     container.addView(viewList.get(position));  
  5.   
  6.     //把当前新增视图的位置(position)作为Key传过去  
  7.     return position;  
  8. }  

我们在上讲也讲了在这个函数中Key是作为返回值与当前装入Container中的视图对应起来的。所以在这里我们返回postion与container.addView(viewList.get(position));里的viewList.get(position)这个视图对应起来。
2、isViewFromObject ()

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. @Override  
  2. public boolean isViewFromObject(View arg0, Object arg1) {  
  3.     // TODO Auto-generated method stub  
  4.     //根据传来的key,找到view,判断与传来的参数View arg0是不是同一个视图  
  5.     return arg0 == viewList.get((int)Integer.parseInt(arg1.toString()));  
  6. }  

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

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

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

  

这里只所以与上章不一样,仅仅只有上部分一部分的地方才有滑动切换,是因为我更改了布局文件:

[html]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  2.     xmlns:tools="http://schemas.android.com/tools"  
  3.     android:layout_width="match_parent"  
  4.     android:layout_height="match_parent"  
  5.     tools:context="com.example.testviewpage_2.MainActivity" >  
  6.   
  7.     <android.support.v4.view.ViewPager  
  8.         android:id="@+id/viewpager"  
  9.         android:layout_width="wrap_content"  
  10.         android:layout_height="200dip"  
  11.         android:layout_gravity="center" />  
  12.   
  13. </RelativeLayout>  
这里将layout_height更改为200dip,只所以这么做,是为了告诉大家,只要在想要实现滑动切换的地方添加上<android.support.v4.view.ViewPager />就可以实现切换,无所谓位置和大小,跟普通控件一样!!!!!!


前言:在前两篇文章中,我们讲解了滑动页面的的实现方法与四大函数的意义,但有时,仅仅实现页面滑动是不够的,还要有标题栏才会显得更友好。所以在这篇文章中,我将会向大家展示在android.support.v4包中的两个控件PagerTabStrip与PagerTitleStrip,他们都是用来实现标题栏的,但各自有些不同,在这篇文章中,我们就讲讲它们各自都能实现怎样的功能,又有哪些异同点。


相关文章:

1、《ViewPager 详解(一)---基本入门》

2、《ViewPager 详解(二)---详解四大函数》

3、《ViewPager 详解(三)---PagerTabStrip与PagerTitleStrip添加标题栏的异同》

4、《ViewPager 详解(四)----自主实现滑动指示条》

5、《ViewPager 详解(五)-----使用Fragment实现ViewPager滑动》


一、PagerTitleStrip

先看个简单的,先上个效果图,吸引大家一下眼球。

三个页面间的滑动,此时是带着上面的标题一块滑动的。

  

看一下android 对于PagerTabStrip的官方解释:

Class Overview


PagerTitleStrip is a non-interactive indicator of the current, next, and previous pages of a ViewPager. It is intended to be used as a child view of a ViewPager widget in your XML layout. Add it as a child of a ViewPager in your layout file and set its android:layout_gravity to TOP or BOTTOM to pin it to the top or bottom of the ViewPager. The title from each page is supplied by the methodgetPageTitle(int) in the adapter supplied to the ViewPager.

For an interactive indicator, see PagerTabStrip.

翻译:

PagerTabStrip是ViewPager的一个关于当前页面、上一个页面和下一个页面的一个非交互的指示器。它经常作为ViewPager控件的一个子控件被被添加在XML布局文件中。在你的布局文件中,将它作为子控件添加在ViewPager中。而且要将它的 android:layout_gravity 属性设置为TOP或BOTTOM来将它显示在ViewPager的顶部或底部。每个页面的标题是通过适配器的getPageTitle(int)函数提供给ViewPager的。


我可能译的不大通顺,这里英文也难度不大,大家应该也能看得懂,但我还是着重讲两点:

1、首先,文中提到:在你的布局文件中,将它作为子控件添加在ViewPager中。

2、第二,标题的获取,是重写适配器的getPageTitle(int)函数来获取的。


根据这两点,我们就可以看代码了:

1、XML布局文件:

[html]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  2.     xmlns:tools="http://schemas.android.com/tools"  
  3.     android:layout_width="match_parent"  
  4.     android:layout_height="match_parent"  
  5.     tools:context="com.example.testviewpage_2.MainActivity" >  
  6.   
  7.     <android.support.v4.view.ViewPager  
  8.         android:id="@+id/viewpager"  
  9.         android:layout_width="wrap_content"  
  10.         android:layout_height="200dip"  
  11.         android:layout_gravity="center">  
  12.           
  13.         <android.support.v4.view.PagerTitleStrip  
  14.             android:id="@+id/pagertitle"    
  15.             android:layout_width="wrap_content"    
  16.             android:layout_height="wrap_content"    
  17.             android:layout_gravity="top"  
  18.             />  
  19.           
  20.     </android.support.v4.view.ViewPager>  
  21.   
  22. </RelativeLayout>  
清楚的看到我们将.PagerTitleStrip将其作为ViewPager的子控件直接嵌入其中;这是第一步;当然android:layout_gravity=""的值要设置为top或bottom。将标题栏显示在顶部或底部。

2、重写适配器的getPageTitle()函数

便于大家有个整体认识,先贴全局代码,然后再逐个讲,这段代码是在《ViewPager 详解(二)---详解四大函数》 直接更改来的,如果不太明白,先看看这篇文章。

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. package com.example.testviewpage_2;  
  2. /** 
  3.  * @author  harvic 
  4.  * @date 2014.8.12 
  5.  */  
  6. import java.util.ArrayList;  
  7. import java.util.List;  
  8. import android.app.Activity;  
  9. import android.os.Bundle;  
  10. import android.support.v4.view.PagerAdapter;  
  11. import android.support.v4.view.PagerTitleStrip;  
  12. import android.support.v4.view.ViewPager;  
  13. import android.view.LayoutInflater;  
  14. import android.view.View;  
  15. import android.view.ViewGroup;  
  16.   
  17. public class MainActivity extends Activity {  
  18.   
  19.     private View view1, view2, view3;  
  20.     private List<View> viewList;// view数组  
  21.     private ViewPager viewPager; // 对应的viewPager  
  22.       
  23.     private List<String> titleList;  //标题列表数组  
  24.       
  25.     @Override  
  26.     protected void onCreate(Bundle savedInstanceState) {  
  27.         super.onCreate(savedInstanceState);  
  28.         setContentView(R.layout.activity_main);  
  29.         viewPager = (ViewPager) findViewById(R.id.viewpager);  
  30.         LayoutInflater inflater = getLayoutInflater();  
  31.         view1 = inflater.inflate(R.layout.layout1, null);  
  32.         view2 = inflater.inflate(R.layout.layout2, null);  
  33.         view3 = inflater.inflate(R.layout.layout3, null);  
  34.   
  35.         viewList = new ArrayList<View>();// 将要分页显示的View装入数组中  
  36.         viewList.add(view1);  
  37.         viewList.add(view2);  
  38.         viewList.add(view3);  
  39.           
  40.         titleList = new ArrayList<String>();// 每个页面的Title数据  
  41.         titleList.add("王鹏");  
  42.         titleList.add("姜语");  
  43.         titleList.add("结婚");  
  44.   
  45.         PagerAdapter pagerAdapter = new PagerAdapter() {  
  46.   
  47.             @Override  
  48.             public boolean isViewFromObject(View arg0, Object arg1) {  
  49.                 // TODO Auto-generated method stub  
  50.                 //根据传来的key,找到view,判断与传来的参数View arg0是不是同一个视图  
  51.                 return arg0 == viewList.get((int)Integer.parseInt(arg1.toString()));  
  52.             }  
  53.   
  54.             @Override  
  55.             public int getCount() {  
  56.                 // TODO Auto-generated method stub  
  57.                 return viewList.size();  
  58.             }  
  59.   
  60.             @Override  
  61.             public void destroyItem(ViewGroup container, int position,  
  62.                     Object object) {  
  63.                 // TODO Auto-generated method stub  
  64.                 container.removeView(viewList.get(position));  
  65.             }  
  66.   
  67.             @Override  
  68.             public Object instantiateItem(ViewGroup container, int position) {  
  69.                 // TODO Auto-generated method stub  
  70.                 container.addView(viewList.get(position));  
  71.                   
  72.                 //把当前新增视图的位置(position)作为Key传过去  
  73.                 return position;  
  74.             }  
  75.               
  76.             @Override  
  77.             public CharSequence getPageTitle(int position) {  
  78.                 // TODO Auto-generated method stub  
  79.                 return titleList.get(position);  
  80.             }  
  81.         };  
  82.   
  83.         viewPager.setAdapter(pagerAdapter);  
  84.   
  85.     }  
  86.   
  87. }  
相比较《ViewPager 详解(二)---详解四大函数》这里作了一点更改:

1、变量

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. private List<String> titleList;  //标题列表数组  
申请了一个String数组,用来存储三个页面所对应的标题的

2、初始化

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. titleList = new ArrayList<String>();// 每个页面的Title数据  
  2. titleList.add("王鹏");  
  3. titleList.add("姜语");  
  4. titleList.add("结婚");  
在初始化阶段增加了这么一段初始化数组的代码。

3、重写CharSequence getPageTitle(int )函数

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. @Override  
  2. public CharSequence getPageTitle(int position) {  
  3.     // TODO Auto-generated method stub  
  4.     return titleList.get(position);  
  5. }  
根据位置返回当前所对应的标题。


大家可以看到,其实这里仅仅只重写了getPageTitle()函数,将其根据不同的位置返回不同的字符串就可以实现上面的标题栏功能。第一和第二步有关数组和初始化,其实都是这了这一步,其实我们完全可以用下面这个代码来取代它们:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. @Override  
  2. public CharSequence getPageTitle(int position) {  
  3.     // TODO Auto-generated method stub  
  4.     switch (position) {  
  5.     case 0:  
  6.         return "王鹏";  
  7.     case 1:  
  8.         return "姜语";  
  9.     case 2:  
  10.         return "结婚";  
  11.   
  12.     default:  
  13.         return "";  
  14.     }  
  15. }  
这样效果是一样一样的,只是代码不好维护而已。好了,有关PagerTabStrip的问题,我们就先说到这。

二、PagerTabStrip

同样,先看个PagerTabStrip做出来的效果是怎样的。

此例是以《ViewPager 详解(一)---基本入门》为基础,更改而成;

    

可能看不出太大区别,其实这两个实现的效果基本差不多,但有两点不同:

1、PagerTabStrip在当前页面下,会有一个下划线条来提示当前页面的Tab是哪个。

2、PagerTabStrip的Tab是可以点击的,当用户点击某一个Tab时,当前页面就会跳转到这个页面,而PagerTitleStrip则没这个功能。


同样,先看看官方对PagerTabStrip的解释:

Class Overview


PagerTabStrip is an interactive indicator of the current, next, and previous pages of a ViewPager. It is intended to be used as a child view of a ViewPager widget in your XML layout. Add it as a child of a ViewPager in your layout file and set its android:layout_gravity to TOP or BOTTOM to pin it to the top or bottom of the ViewPager. The title from each page is supplied by the methodgetPageTitle(int) in the adapter supplied to the ViewPager.

For a non-interactive indicator, see PagerTitleStrip.

翻译:

PagerTabStrip是ViewPager的一个关于当前页面、上一个页面和下一个页面的一个可交互的指示器。它经常作为ViewPager控件的一个子控件被被添加在XML布局文件中。在你的布局文件中,将它作为子控件添加在ViewPager中。而且要将它的 android:layout_gravity 属性设置为TOP或BOTTOM来将它显示在ViewPager的顶部或底部。每个页面的标题是通过适配器的getPageTitle(int)函数提供给ViewPager的。

可以看到,除了第一句以外的其它句与PagerTitleStrip的解释完全相同。即用法也是相同的。只是PagerTabStrip是可交互的,而PagerTitleStrip是不可交互的区别。对于区别在哪些位置,即是上面的两点(是否可点击与下划线指示条)。


用法与PagerTitleStrip完全相同,即:

1、首先,文中提到:在你的布局文件中,将它作为子控件添加在ViewPager中。

2、第二,标题的获取,是重写适配器的getPageTitle(int)函数来获取的。

看看实例:

1、XML布局

[html]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  2.     xmlns:tools="http://schemas.android.com/tools"  
  3.     android:layout_width="match_parent"  
  4.     android:layout_height="match_parent"  
  5.     tools:context="com.example.testviewpage_2.MainActivity" >  
  6.   
  7.     <android.support.v4.view.ViewPager  
  8.         android:id="@+id/viewpager"  
  9.         android:layout_width="wrap_content"  
  10.         android:layout_height="wrap_content"  
  11.         android:layout_gravity="center">  
  12.           
  13.                 <android.support.v4.view.PagerTabStrip  
  14.             android:id="@+id/pagertab"  
  15.             android:layout_width="match_parent"  
  16.             android:layout_height="wrap_content"   
  17.             android:layout_gravity="top"/>  
  18.           
  19.     </android.support.v4.view.ViewPager>  
  20.   
  21. </RelativeLayout>  
可以看到,同样,是将PagerTabStrip作为ViewPager的一个子控件直接插入其中,当然android:layout_gravity=""的值一样要设置为top或bottom。

2、重写适配器的getPageTitle()函数

全部代码:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. package com.example.testviewpage_2;  
  2.   
  3. /** 
  4.  * @author  harvic 
  5.  * @date 2014.8.13 
  6.  */  
  7. import java.util.ArrayList;  
  8. import java.util.List;  
  9.   
  10. import android.app.Activity;  
  11. import android.os.Bundle;  
  12. import android.support.v4.view.PagerAdapter;  
  13. import android.support.v4.view.ViewPager;  
  14. import android.view.LayoutInflater;  
  15. import android.view.View;  
  16. import android.view.ViewGroup;  
  17.   
  18. public class MainActivity extends Activity {  
  19.   
  20.     private View view1, view2, view3;  
  21.     private List<View> viewList;// view数组  
  22.     private ViewPager viewPager; // 对应的viewPager  
  23.   
  24.     private List<String> titleList;  
  25.   
  26.     @Override  
  27.     protected void onCreate(Bundle savedInstanceState) {  
  28.         super.onCreate(savedInstanceState);  
  29.         setContentView(R.layout.activity_main);  
  30.   
  31.         viewPager = (ViewPager) findViewById(R.id.viewpager);  
  32.         LayoutInflater inflater = getLayoutInflater();  
  33.         view1 = inflater.inflate(R.layout.layout1, null);  
  34.         view2 = inflater.inflate(R.layout.layout2, null);  
  35.         view3 = inflater.inflate(R.layout.layout3, null);  
  36.   
  37.         viewList = new ArrayList<View>();// 将要分页显示的View装入数组中  
  38.         viewList.add(view1);  
  39.         viewList.add(view2);  
  40.         viewList.add(view3);  
  41.   
  42.         titleList = new ArrayList<String>();// 每个页面的Title数据  
  43.         titleList.add("王鹏");  
  44.         titleList.add("姜语");  
  45.         titleList.add("结婚");  
  46.   
  47.         PagerAdapter pagerAdapter = new PagerAdapter() {  
  48.   
  49.             @Override  
  50.             public boolean isViewFromObject(View arg0, Object arg1) {  
  51.                 // TODO Auto-generated method stub  
  52.                 return arg0 == arg1;  
  53.             }  
  54.   
  55.             @Override  
  56.             public int getCount() {  
  57.                 // TODO Auto-generated method stub  
  58.                 return viewList.size();  
  59.             }  
  60.   
  61.             @Override  
  62.             public void destroyItem(ViewGroup container, int position,  
  63.                     Object object) {  
  64.                 // TODO Auto-generated method stub  
  65.                 container.removeView(viewList.get(position));  
  66.             }  
  67.   
  68.             @Override  
  69.             public Object instantiateItem(ViewGroup container, int position) {  
  70.                 // TODO Auto-generated method stub  
  71.                 container.addView(viewList.get(position));  
  72.   
  73.                 return viewList.get(position);  
  74.             }  
  75.   
  76.             @Override  
  77.             public CharSequence getPageTitle(int position) {  
  78.                   
  79.                 return titleList.get(position);  
  80.             }  
  81.         };  
  82.   
  83.         viewPager.setAdapter(pagerAdapter);  
  84.   
  85.     }  
  86.   
  87. }  
这里的代码与PagerTitleStrip的完全相同,就不再讲解了。

就这样,我们就讲完了有关PagerTabStrip的简单使用方法。下面讲一讲PagerTabStrip的扩展。

3、扩展:PagerTabStrip属性更改

在源码中,大家可以看到有个工程叫TestViewPage_PagerTabStrip_extension,运行一下,效果是这样的:

    

在上面两个图中可以看到,我更改了两个地方:

1、下划线颜色,原生是黑色,我变成了绿色;

2、在Tab标题前加了一个图片;

下面说说是如何更改的:

1、更改下划线颜色:

主要靠PagerTabStrip的setTabIndicatorColorResource方法;

代码如下:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. pagerTabStrip = (PagerTabStrip) findViewById(R.id.pagertab);  
  2. pagerTabStrip.setTabIndicatorColorResource(R.color.green);  

2、添加标题——重写适配器CharSequence getPageTitle(int)方法

在CharSequence getPageTitle(int position)方法返回值是,我们不返回String对象,而采用SpannableStringBuilder来构造了下包含图片的扩展String对像;

具体代码如下,不再细讲,大家可以看看SpannableStringBuilder的使用方法,就可理解了。

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. @Override  
  2. public CharSequence getPageTitle(int position) {  
  3.   
  4.     SpannableStringBuilder ssb = new SpannableStringBuilder("  "+titleList.get(position)); // space added before text  
  5.                                         // for  
  6.     Drawable myDrawable = getResources().getDrawable(  
  7.             R.drawable.ic_launcher);  
  8.     myDrawable.setBounds(00, myDrawable.getIntrinsicWidth(),  
  9.             myDrawable.getIntrinsicHeight());  
  10.     ImageSpan span = new ImageSpan(myDrawable,  
  11.             ImageSpan.ALIGN_BASELINE);  
  12.   
  13.     ForegroundColorSpan fcs = new ForegroundColorSpan(Color.GREEN);// 字体颜色设置为绿色  
  14.     ssb.setSpan(span, 01, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);// 设置图标  
  15.     ssb.setSpan(fcs, 1, ssb.length(),  
  16.             Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);// 设置字体颜色  
  17.     ssb.setSpan(new RelativeSizeSpan(1.2f), 1, ssb.length(),  
  18.             Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);  
  19.     return ssb;  
  20. }  

三、总结

通过前面的讲解,我们应该清楚的认识到PagerTabStrip与PagerTitleStrip在添加标题栏的异同,但他们实现的标题栏效果很不好,不能指定一个页面一次显示一个,或者全部显示,而且标题还滑动。所以注定主流的App都没有用这个玩意的。所以这里也只是一个过渡,在开发中,我们也不建议使用这两个东东。


为什么无法改变PagerTabStrip的滑动特性,看这个贴子:《Fixed Tabs with android.support.v4.view.PagerTabStrip or ViewPagerIndicator》


参考文章:

《Android多屏滑动:ViewPager基础使用及PagerTabStrip先天缺陷(附源码)》

《android:修改PagerTabStrip中的背景颜色,标题字体的样式、颜色和图标以及指示条的颜色》


所有源码打包在一起,分为三个:

1、TestViewPage_pagerTitleStrip:pagerTitleStrip实现实例

2、TestViewPage_PagerTabStrip :PagerTabStrip实现实例

3、TestViewPage_PagerTabStrip_extension:PagerTabStrip的扩展实现


前言:前面我们用了三篇的时间讲述了有关ViewPager的基础知识,到这篇就要进入点实际的了。在第三篇《ViewPager 详解(三)---PagerTabStrip与PagerTitleStrip添加标题栏的异同》中,我们说了,PagerTabStrip和PagerTitleStrip都不适合用在实际用途中,当要在实际运用中,我们就要自己去实现相关的功能。这篇文章中单纯讲述划动指示条的实现方法,而对于交互Tab的实现,就不再讲解,最后给出网上的一段源码,大家可以去研究一下,有关交互Tab的实现原理是一样的,难度不大。


相关文章:

1、《ViewPager 详解(一)---基本入门》

2、《ViewPager 详解(二)---详解四大函数》

3、《ViewPager 详解(三)---PagerTabStrip与PagerTitleStrip添加标题栏的异同》

4、《ViewPager 详解(四)----自主实现滑动指示条》

5、《ViewPager 详解(五)-----使用Fragment实现ViewPager滑动》


先上本篇效果图:

  

一、XML布局

布局代码如下:

[html]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  2.     xmlns:tools="http://schemas.android.com/tools"  
  3.     android:layout_width="match_parent"  
  4.     android:layout_height="match_parent"  
  5.     android:orientation="vertical"  
  6.     tools:context="com.example.testviewpage_2.MainActivity" >  
  7.       
  8.      <ImageView  
  9.         android:id="@+id/cursor"  
  10.         android:layout_width="fill_parent"  
  11.         android:layout_height="wrap_content"  
  12.         android:scaleType="matrix"  
  13.         android:src="@drawable/a" />  
  14.   
  15.     <android.support.v4.view.ViewPager  
  16.         android:id="@+id/viewpager"  
  17.         android:layout_width="wrap_content"  
  18.         android:layout_height="wrap_content"  
  19.         android:layout_gravity="center"/>  
  20.   
  21. </LinearLayout>  
采用线性垂直布局,在滑动页面的上方添加一个小水平条。

二、JAVA代码

本例代码是根据《ViewPager 详解(一)---基本入门》 更改而来。

先给出全部代码,然后再逐步讲解。

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. public class MainActivity extends Activity {  
  2.   
  3.     private View view1, view2, view3;  
  4.     private List<View> viewList;// view数组  
  5.     private ViewPager viewPager; // 对应的viewPager  
  6.   
  7.     private ImageView cursor;  
  8.     private int bmpw = 0// 游标宽度  
  9.     private int offset = 0;// // 动画图片偏移量  
  10.     private int currIndex = 0;// 当前页卡编号  
  11.   
  12.     @Override  
  13.     protected void onCreate(Bundle savedInstanceState) {  
  14.         super.onCreate(savedInstanceState);  
  15.         setContentView(R.layout.activity_main);  
  16.   
  17.         viewPager = (ViewPager) findViewById(R.id.viewpager);  
  18.         LayoutInflater inflater = getLayoutInflater();  
  19.         view1 = inflater.inflate(R.layout.layout1, null);  
  20.         view2 = inflater.inflate(R.layout.layout2, null);  
  21.         view3 = inflater.inflate(R.layout.layout3, null);  
  22.   
  23.         viewList = new ArrayList<View>();// 将要分页显示的View装入数组中  
  24.         viewList.add(view1);  
  25.         viewList.add(view2);  
  26.         viewList.add(view3);  
  27.   
  28.         //初始化指示器位置  
  29.         initCursorPos();  
  30.           
  31.         viewPager.setAdapter(new MyPagerAdapter(viewList));  
  32.         viewPager.setOnPageChangeListener(new MyPageChangeListener());  
  33.   
  34.     }  
  35.       
  36.     //初始化指示器位置  
  37.     public void initCursorPos() {  
  38.         // 初始化动画  
  39.         cursor = (ImageView) findViewById(R.id.cursor);  
  40.         bmpw = BitmapFactory.decodeResource(getResources(), R.drawable.a)  
  41.                 .getWidth();// 获取图片宽度  
  42.   
  43.         DisplayMetrics dm = new DisplayMetrics();  
  44.         getWindowManager().getDefaultDisplay().getMetrics(dm);  
  45.         int screenW = dm.widthPixels;// 获取分辨率宽度  
  46.         offset = (screenW / viewList.size() - bmpw) / 2;// 计算偏移量  
  47.   
  48.         Matrix matrix = new Matrix();  
  49.         matrix.postTranslate(offset, 0);  
  50.         cursor.setImageMatrix(matrix);// 设置动画初始位置  
  51.     }  
  52.       
  53.   
  54.     //页面改变监听器  
  55.     public class MyPageChangeListener implements OnPageChangeListener {  
  56.   
  57.         int one = offset * 2 + bmpw;// 页卡1 -> 页卡2 偏移量  
  58.         int two = one * 2;// 页卡1 -> 页卡3 偏移量  
  59.   
  60.         @Override  
  61.         public void onPageSelected(int arg0) {  
  62.             Animation animation = null;  
  63.             switch (arg0) {  
  64.             case 0:  
  65.                 if (currIndex == 1) {  
  66.                     animation = new TranslateAnimation(one, 000);  
  67.                 } else if (currIndex == 2) {  
  68.                     animation = new TranslateAnimation(two, 000);  
  69.                 }  
  70.                 break;  
  71.             case 1:  
  72.                 if (currIndex == 0) {  
  73.                     animation = new TranslateAnimation(offset, one, 00);  
  74.                 } else if (currIndex == 2) {  
  75.                     animation = new TranslateAnimation(two, one, 00);  
  76.                 }  
  77.                 break;  
  78.             case 2:  
  79.                 if (currIndex == 0) {  
  80.                     animation = new TranslateAnimation(offset, two, 00);  
  81.                 } else if (currIndex == 1) {  
  82.                     animation = new TranslateAnimation(one, two, 00);  
  83.                 }  
  84.                 break;  
  85.             }  
  86.             currIndex = arg0;  
  87.             animation.setFillAfter(true);// True:图片停在动画结束位置  
  88.             animation.setDuration(300);  
  89.             cursor.startAnimation(animation);  
  90.         }  
  91.   
  92.         @Override  
  93.         public void onPageScrolled(int arg0, float arg1, int arg2) {  
  94.         }  
  95.   
  96.         @Override  
  97.         public void onPageScrollStateChanged(int arg0) {  
  98.         }  
  99.     }  
  100.       
  101.       
  102.       
  103.       
  104.   
  105.     /** 
  106.      * ViewPager适配器 
  107.      */  
  108.     public class MyPagerAdapter extends PagerAdapter {  
  109.         public List<View> mListViews;  
  110.   
  111.         public MyPagerAdapter(List<View> mListViews) {  
  112.             this.mListViews = mListViews;  
  113.         }  
  114.   
  115.         @Override  
  116.         public boolean isViewFromObject(View arg0, Object arg1) {  
  117.             // TODO Auto-generated method stub  
  118.             return arg0 == arg1;  
  119.         }  
  120.   
  121.         @Override  
  122.         public int getCount() {  
  123.             // TODO Auto-generated method stub  
  124.             return mListViews.size();  
  125.         }  
  126.   
  127.         @Override  
  128.         public void destroyItem(ViewGroup container, int position, Object object) {  
  129.             // TODO Auto-generated method stub  
  130.             container.removeView(mListViews.get(position));  
  131.         }  
  132.   
  133.         @Override  
  134.         public Object instantiateItem(ViewGroup container, int position) {  
  135.             // TODO Auto-generated method stub  
  136.             container.addView(mListViews.get(position));  
  137.   
  138.             return mListViews.get(position);  
  139.         }  
  140.     }  
  141.   
  142. }  
从易到难一步步来讲。

1、MyPagerAdapter类


在前几篇中,我们对于适配器的实现总是new一个PageAdapter的实例。我们这里做了一点稍微的更改,将其集合成一个类,内容都没变,只是多了一个构造函数而已。所以针对这个类的具体代码,我就不再细讲,如果对其中的复写的函数为什么要这么写不理解的同学,请看《ViewPager 详解(二)---详解四大函数》

2、initCursorPos()---初始化指示器位置

游标在初始化显示时,我们要根据屏幕宽度来显示游标位置。先看看这部分代码:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. //初始化指示器位置  
  2. public void initCursorPos() {  
  3.     // 初始化动画  
  4.     cursor = (ImageView) findViewById(R.id.cursor);  
  5.     bmpw = BitmapFactory.decodeResource(getResources(), R.drawable.a)  
  6.             .getWidth();// 获取图片宽度  
  7.   
  8.     DisplayMetrics dm = new DisplayMetrics();  
  9.     getWindowManager().getDefaultDisplay().getMetrics(dm);  
  10.     int screenW = dm.widthPixels;// 获取分辨率宽度  
  11.     offset = (screenW / viewList.size() - bmpw) / 2;// 计算偏移量  
  12.   
  13.     Matrix matrix = new Matrix();  
  14.     matrix.postTranslate(offset, 0);  
  15.     cursor.setImageMatrix(matrix);// 设置动画初始位置  
  16. }  

可能有些同学不明白的位置在于,初始化位置的偏移量为什么这么算,下面,我画了张图,看下就应该明白了。


最后对于偏移的方法,可用的很多,这里仿网上的代码用了matrix;当然大家可以用其它的偏移方法,一样。

3、MyPageChangeListener()---页面改变监听器

代码如下 :

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. public class MyPageChangeListener implements OnPageChangeListener {  
  2.   
  3.     int one = offset * 2 + bmpw;// 页卡1 -> 页卡2 偏移量  
  4.     int two = one * 2;// 页卡1 -> 页卡3 偏移量  
  5.   
  6.     @Override  
  7.     public void onPageSelected(int arg0) {  
  8.         Animation animation = null;  
  9.         switch (arg0) {  
  10.         case 0:  
  11.             if (currIndex == 1) {  
  12.                 animation = new TranslateAnimation(one, 000);  
  13.             } else if (currIndex == 2) {  
  14.                 animation = new TranslateAnimation(two, 000);  
  15.             }  
  16.             break;  
  17.         case 1:  
  18.             if (currIndex == 0) {  
  19.                 animation = new TranslateAnimation(offset, one, 00);  
  20.             } else if (currIndex == 2) {  
  21.                 animation = new TranslateAnimation(two, one, 00);  
  22.             }  
  23.             break;  
  24.         case 2:  
  25.             if (currIndex == 0) {  
  26.                 animation = new TranslateAnimation(offset, two, 00);  
  27.             } else if (currIndex == 1) {  
  28.                 animation = new TranslateAnimation(one, two, 00);  
  29.             }  
  30.             break;  
  31.         }  
  32.         currIndex = arg0;  
  33.         animation.setFillAfter(true);// True:图片停在动画结束位置  
  34.         animation.setDuration(300);  
  35.         cursor.startAnimation(animation);  
  36.     }  
原理是这样,根据滑动到的页面,把游标滑动找指定位置。
这里可能有难度的地方在于,数学……

我画了一张图,解释从第一个页面到第二个页面时的距离为什么是“游标宽度+offset*2”,其它距离类似。



这篇就到这了,时间比较紧,而且这个难度不太大,讲的可能不太细。


源码中,给大家列出了一个有Tab交互的Demo,图片如下:

  


相关文章:

《Android ViewPager使用详解》

《Android ViewPager多页面滑动切换以及动画效果》

《Android多屏滑动:ViewPager基础使用及PagerTabStrip先天缺陷(附源码)》



源码包含:

1、TestViewPage_scroll_cursor:文中示例源码

2、DWinterTabDemo:带Tab交互的Demo


源码下载地址:http://download.csdn.net/detail/harvic880925/7758941


请大家尊重原创者版权,转载请标明出处:http://blog.csdn.net/harvic880925/article/details/38557517  谢谢



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值