android android中viewpagerr怎么放两个activity

下次自动登录
关注移动互联网和移动APP开发工具、开发框架、测试工具、微信开发、Android源码、Android开源类库以及各种开源组件的IT科技网站
现在的位置:
android.support.v4.view.ViewPager 如何动态更换显示内容
看一段简单的代码,在一个pager里面显示两个TextView
List items = new ArrayList();
adapter = new MyPagerAdapter();
TextView tv = new TextView(getActivity());
tv.setText(第一页);
items.add(tv);
tv = new TextView(getActivity());
tv.setText(第二页);
items.add(tv);
pager.setAdapter(adapter);
Adapter代码
class MyPagerAdapter extends PagerAdapter{
public Object instantiateItem(ViewGroup container, int position) {
View layout = items.get(position);
container.addView(layout);
public void destroyItem(ViewGroup container, int position, Object object) {
View layout = items.get(position);
container.removeView(layout);
public boolean isViewFromObject(View arg0, Object arg1) {
return arg0 == arg1;
public int getCount() {
return items.size();
public int getItemPosition(Object object) {
// TODO Auto-generated method stub
return super.getItemPosition(object);
代码运行正常,左右滑动都OK。
好,现在需求来了,我需要把“第一页”和“第二页”干掉,再重新添加两个TextView,分别是“第三页”和“第四页”,于是按常理写了如下代码
items.clear();
TextView tv = new TextView(getActivity());
tv.setText(第三页);
items.add(tv);
tv = new TextView(getActivity());
tv.setText(第四页);
items.add(tv);
adapter.notifyDataSetChanged();
我们在使用ListView的时候,改变数据源的数据,然后通知adpater去更新,就可以正常显示,可是在ViewPager这不好使,上面代码执行后,没有任何变化
那我们想是不是ViewPager需要清一下原有的试图呢,好,再加一句
pager.removeAllViews();
再次运行,可好,一片空白,啥也没了,真干净!
蒙了吧,到底什么原因,就是getItemPosition,让我看看当ViewPager的Adapter发生变化时,到底干了啥,Adapter执行notifyDataSetChanged时,会触发ViewPager的dataSetChanged方法,下面是,:
void dataSetChanged() {
// This method only gets called if our observer is attached, so mAdapter is non-null.
final int adapterCount = mAdapter.getCount();
mExpectedAdapterCount = adapterC
boolean needPopulate = mItems.size() & mOffscreenPageLimit * 2 + 1 &&
mItems.size() & adapterC
int newCurrItem = mCurI
boolean isUpdating =
for (int i = 0; i & mItems.size(); i++) {
final ItemInfo ii = mItems.get(i);
final int newPos = mAdapter.getItemPosition(ii.object);
//看这句话,如果是PagerAdapter.POSITION_UNCHANGED标志,直接返回,不做任何处理
if (newPos == PagerAdapter.POSITION_UNCHANGED) {
//只有返回PagerAdapter.POSITION_NONE标志时,才会对内部视图进行调整
if (newPos == PagerAdapter.POSITION_NONE) {
//先从数据源中清除
mItems.remove(i);
if (!isUpdating) {
mAdapter.startUpdate(this);
isUpdating =
//在调用Adapter的destroyItem,去销毁视图
mAdapter.destroyItem(this, ii.position, ii.object);
needPopulate =
if (mCurItem == ii.position) {
// Keep the current item in the valid range
newCurrItem = Math.max(0, Math.min(mCurItem, adapterCount - 1));
needPopulate =
if (ii.position != newPos) {
if (ii.position == mCurItem) {
// Our current item changed position. Follow it.
newCurrItem = newP
ii.position = newP
needPopulate =
if (isUpdating) {
mAdapter.finishUpdate(this);
Collections.sort(mItems, COMPARATOR);
if (needPopulate) {
// Reset o populate will recompute them.
final int childCount = getChildCount();
for (int i = 0; i & childC i++) {
final View child = getChildAt(i);
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
if (!lp.isDecor) {
lp.widthFactor = 0.f;
setCurrentItemInternal(newCurrItem, false, true);
requestLayout();
PagerAdapter.POSITION_UNCHANGED,这个标记决定着视图是否被重新创建,Apdapter默认的代码如下
public int getItemPosition(Object object) {
return POSITION_UNCHANGED;
默认返回POSITION_UNCHANGED,所以如果你不对Adapter的getItemPosition进行重写的画,就会出现无法更改内部视图效果的问题。下面对从PagerAdapter继承的代码进行改造,加上对getItemPosition的修改,让他直接返回POSITION_NONE,POSITION_NONE每次数据发生变化,都会引起视图的重建,比较消耗内存,所以不需要变化内部视图时,避免使用。
public int getItemPosition(Object object) {
// TODO Auto-generated method stub
return POSITION_NONE;
如果返回了POSITION_NONE,但是没有pager.removeAllViews(),那么“第一页”和“第二页”没有消失,“第三页”和“第四页”也上去了,分别和前两页重合了,看图
如果返回了POSITION_UNCHANGED,但是没有pager.removeAllViews(),那么看不到任何变化。
【上篇】【下篇】
您可能还会对这些文章感兴趣!
同分类最新文章ViewPager的使用(二)配合FragmentPagerAdapter
先说一段题外话。我们在进行android开发的时候发现,activity是与界面相关的,view及其派生类也是与界面相关的,fragment也是与界面相关的,那他们直接的联系和区别在哪呢。我们知道activity并不直接生成界面,他与view及其派生类关联才能产生界面,acitivity有自己的生命周期,掌管着界面从创建到消亡的过程,用户对应用程序的操作(比如按键,触屏)都要通过acitivity来分发和处理,activity建立view与监听器及之间的关联,从activity的这些作用来看与mvc架构中的c(Controller)作用相似,而view及其派生类当然就是mvc架构中的v。
我们再来看fragment,fragment有自己的生命周期(虽然它的生命周期依赖activity的生命周期),它能够管理属于它自己的view,他有自己的用户交互,这么看它也像是一个mvc中的c,但是它又可以像view一样加入到acitivity的布局中,这又像是一个mvc架构中的v。因此fragment是为了简化actvity与view之间的交互而将activity对用户交互的逻辑模块化进行的封装,它的好处是:1&简化activity的逻辑控制
2&这些模块化的fragment也更利于复用。
& & Fragment有如下特点:
1&Fragment表现为一个activity用户界面的一部分
2&一个activity可以有多个fragment
3&可以在多个activity中复用fragment
4&fragment有自己的生命周期
5&fragment有自己的事件处理
6&activity运行中,可以添加,移除一个fragment
7&fragment的生命周期有其宿主activity控制
回到正题,ViewPager配合FragmentPagerAdapter如何使用,我们通过下面的例子来说明。
界面布局文件
&?xml version="1.0"
encoding="utf-8"?&
&LinearLayout
xmlns:android="/apk/res/android"
android:id="@+id/linear"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" &
&android.support.v4.view.ViewPager
& android:id="@+id/viewpager1"
& android:layout_width="fill_parent"
& android:layout_height="fill_parent"
&/android.support.v4.view.ViewPager&
&/LinearLayout&
界面实现:
public class PagerAdapterAndActionBarActivity extends Activity
ViewPager viewP
ActionBar mActionB
Fragment1 fragment1;
Fragment2 fragment2;
ArrayList&Fragment&
protected void onCreate(Bundle arg0) {
super.onCreate(arg0);
setContentView(R.layout.block_incoming_call_setting);
// 设置viewPager的适配器
listFragmentsa = new
ArrayList&Fragment&();
fragment1 = new Fragment1();
fragment2 = new Fragment2();
listFragmentsa.add(fragment1);
listFragmentsa.add(fragment2);
MyFragmentPagerAdapter myFragmentPagerAdapter = new
MyFragmentPagerAdapter(getFragmentManager(), listFragmentsa);
viewPager = (ViewPager) findViewById(R.id.viewpager1);
viewPager.setAdapter(myFragmentPagerAdapter);
viewPager.setCurrentItem(0);
// 监听viewPager的变化,ViewPager的变化会同步到ActionBar的tab页
MyOnPageChangeListener myOnPageChangeListener = new
MyOnPageChangeListener();
viewPager.setOnPageChangeListener(myOnPageChangeListener);
// 设置ActionBar的tab页,并且ViewPager会随着Tab的选择变化
mActionBar = getActionBar();
mActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
MyTabListener myTabListener = new
MyTabListener(listFragmentsa);
Tab tab1 = mActionBar.newTab().setText("aaaaaaaa");
Tab tab2 = mActionBar.newTab().setText("bbbbbbbb");
tab1.setTabListener(myTabListener);
tab2.setTabListener(myTabListener);
mActionBar.addTab(tab1);
mActionBar.addTab(tab2);
class MyFragmentPagerAdapter extends FragmentPagerAdapter
private ArrayList&Fragment&
public MyFragmentPagerAdapter(FragmentManager fm,
ArrayList&Fragment& al) {
super(fm);
listFragments =
public MyFragmentPagerAdapter(FragmentManager fm) {
super(fm);
public Fragment getItem(int position) {
return listFragments.get(position);
public int getCount() {
return listFragments.size();
public int getItemPosition(Object object) {
return super.getItemPosition(object);
class MyTabListener implements TabListener {
ArrayList&Fragment&
MyTabListener(ArrayList&Fragment&
mFragments) {
this.mFragments = mF
public void onTabReselected(Tab tab, FragmentTransaction ft)
public void onTabSelected(Tab tab, FragmentTransaction ft)
viewPager.setCurrentItem(tab.getPosition());
public void onTabUnselected(Tab tab, FragmentTransaction ft)
class MyOnPageChangeListener implements OnPageChangeListener
public void onPageScrollStateChanged(int arg0) {
Log.w("xujinqq", "onPageScrollStateChanged");
public void onPageScrolled(int arg0, float arg1, int arg2)
Log.w("xujinqq", "onPageScrolled");
public void onPageSelected(int arg0) {
Log.w("xujinqq", "onPageSelected" + arg0);
// mActionBar.getTabAt(arg0).select();
mActionBar.setSelectedNavigationItem(arg0);
已投稿到:
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。当前访客身份:游客 [
积跬步,至千里!!!!
:红色部分说的很好~
:为什么手动切换一个page后才显示PagerTitleStrip...
:引用来自“算你狠”的评论 Context mContext=nul...
:Context mContext= public FlectionView(Co...
:怎么都没有R.layout.tab1 tab1
:多谢1楼提示
:非常感谢! 今天刚看pull解析搞不太懂,现在看完...
:引用来自“leeyongchao”的评论不是判断中断了吗...
今日访问:72
昨日访问:312
本周访问:3228
本月访问:5839
所有访问:166513
ViewPager的基本使用
发表于2年前( 15:15)&&
阅读(56044)&|&评论()
0人收藏此文章,
& & &ViewPager是android扩展包v4包中的类,这个类可以让用户左右切换当前的view。我们首先来看看API对于这个类的表述:
Layout&manager&that&allows&the&user&to&flip&left&and&right&through&pages&of&data.&You&supply&an&implementation&of&a&PagerAdapter&to&generate&the&pages&that&the&view&shows.
Note&this&class&is&currently&under&early&design&and&development.&The&API&will&likely&change&in&later&updates&of&the&compatibility&library,&requiring&changes&to&the&source&code&of&apps&when&they&are&compiled&against&the&newer&version.
ViewPager&is&most&often&used&in&conjunction&with&Fragment,&which&is&a&convenient&way&to&supply&and&manage&the&lifecycle&of&each&page.&There&are&standard&adapters&implemented&for&using&fragments&with&the&ViewPager,&which&cover&the&most&common&use&cases.&These&are&FragmentPagerAdapter&andFragmentStatePagerA&each&of&these&classes&have&simple&code&showing&how&to&build&a&full&user&interface&with&them.
从这个描述中我们知道几点:
& 1)ViewPager类直接继承了ViewGroup类,所有它是一个容器类,可以在其中添加其他的view类。
& 2)ViewPager类需要一个PagerAdapter适配器类给它提供数据。
& 3)ViewPager经常和Fragment一起使用,并且提供了专门的FragmentPagerAdapter和FragmentStatePagerAdapter类供Fragment中的ViewPager使用。
& &在编写ViewPager的应用的使用,还需要使用两个组件类分别是PagerTitleStrip类和PagerTabStrip类,PagerTitleStrip类直接继承自ViewGroup类,而PagerTabStrip类继承PagerTitleStrip类,所以这两个类也是容器类。但是有一点需要注意,在定义XML的layout的时候,这两个类必须是ViewPager标签的子标签,不然会出错。
layout.xml:
&RelativeLayout&xmlns:android="/apk/res/android"
&&&&xmlns:tools="/tools"
&&&&android:layout_width="match_parent"
&&&&android:layout_height="match_parent"
&&&&tools:context=".MainActivity"&&
&&&&&android.support.v4.view.ViewPager
&&&&&&&&android:id="@+id/viewpager"
&&&&&&&&android:layout_width="wrap_content"
&&&&&&&&android:layout_height="wrap_content"&&
&&&&&&&&&android.support.v4.view.PagerTabStrip
&&&&&&&&&&&&android:id="@+id/tabstrip"
&&&&&&&&&&&&android:layout_width="wrap_content"
&&&&&&&&&&&&android:layout_height="50dip"
&&&&&&&&&&&&android:gravity="center"&/&
&&&&&/android.support.v4.view.ViewPager&
&/RelativeLayout&
MainActivity.java
package&com.example.android_viewpager1;
import&java.util.ArrayL
import&android.annotation.SuppressL
import&android.app.A
import&android.os.B
import&android.support.v4.view.PagerA
import&android.support.v4.view.PagerTabS
import&android.support.v4.view.ViewP
import&android.support.v4.view.ViewPager.OnPageChangeL
import&android.util.L
import&android.view.LayoutI
import&android.view.V
import&android.view.ViewG
public&class&MainActivity&extends&Activity&{
ViewPager&pager&=&
PagerTabStrip&tabStrip&=&
ArrayList&View&&viewContainter&=&new&ArrayList&View&();
ArrayList&String&&titleContainer&=&new&ArrayList&String&();
public&String&TAG&=&"tag";
@SuppressLint("ResourceAsColor")
protected&void&onCreate(Bundle&savedInstanceState)&{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
pager&=&(ViewPager)&this.findViewById(R.id.viewpager);
tabStrip&=&(PagerTabStrip)&this.findViewById(R.id.tabstrip);
//取消tab下面的长横线
tabStrip.setDrawFullUnderline(false);
//设置tab的背景色
tabStrip.setBackgroundColor(this.getResources().getColor(R.color.bg));
//设置当前tab页签的下划线颜色
tabStrip.setTabIndicatorColor(this.getResources().getColor(R.color.red));
tabStrip.setTextSpacing(200);
View&view1&=&LayoutInflater.from(this).inflate(R.layout.tab1,&null);
View&view2&=&LayoutInflater.from(this).inflate(R.layout.tab2,&null);
View&view3&=&LayoutInflater.from(this).inflate(R.layout.tab3,&null);
View&view4&=&LayoutInflater.from(this).inflate(R.layout.tab4,&null);
&&&&&&//viewpager开始添加view
viewContainter.add(view1);
viewContainter.add(view2);
viewContainter.add(view3);
viewContainter.add(view4);
&&&&&&//页签项
titleContainer.add("网易新闻");
titleContainer.add("网易体育");
titleContainer.add("网易财经");
titleContainer.add("网易女人");
pager.setAdapter(new&PagerAdapter()&{
//viewpager中的组件数量
public&int&getCount()&{
return&viewContainter.size();
&&&&&&&&&&//滑动切换的时候销毁当前的组件
public&void&destroyItem(ViewGroup&container,&int&position,
Object&object)&{
((ViewPager)&container).removeView(viewContainter.get(position));
&&&&&&&&&&//每次滑动的时候生成的组件
public&Object&instantiateItem(ViewGroup&container,&int&position)&{
((ViewPager)&container).addView(viewContainter.get(position));
return&viewContainter.get(position);
public&boolean&isViewFromObject(View&arg0,&Object&arg1)&{
return&arg0&==&arg1;
public&int&getItemPosition(Object&object)&{
return&super.getItemPosition(object);
public&CharSequence&getPageTitle(int&position)&{
return&titleContainer.get(position);
pager.setOnPageChangeListener(new&OnPageChangeListener()&{
public&void&onPageScrollStateChanged(int&arg0)&{
Log.d(TAG,&"--------changed:"&+&arg0);
public&void&onPageScrolled(int&arg0,&float&arg1,&int&arg2)&{
Log.d(TAG,&"-------scrolled&arg0:"&+&arg0);
Log.d(TAG,&"-------scrolled&arg1:"&+&arg1);
Log.d(TAG,&"-------scrolled&arg2:"&+&arg2);
public&void&onPageSelected(int&arg0)&{
Log.d(TAG,&"------selected:"&+&arg0);
实现的效果如下:
对于PagerAdapter类,android的文档已经说的很清楚了,必须至少实现如下的4个方法,如果需要更好的扩展也可以实现更多的方法。
public Object instantiateItem(ViewGroup container, int position)
public void destroyItem(ViewGroup container, int position,Object object)&
public int getCount()
public boolean isViewFromObject(View arg0, Object arg1)&
更多开发者职位上
1)">1)">1" ng-class="{current:{{currentPage==page}}}" ng-repeat="page in pages"><li class='page' ng-if="(endIndex<li class='page next' ng-if="(currentPage
相关文章阅读Android控件的新宠儿——ViewPager
Android控件的新宠儿——ViewPager
1 认识一下ViewPager?
ViewPager最早出自4.0版本,那么低版本如何能使用ViewPager呢?为了兼容低版本安卓设备,谷歌官方给我们提供了一个的软件包android.support.v4.view。这个V4包囊了只有在安卓3.0以上可以使用的api,而viewpager就是其中之一。利用它,我们可以做很多事情,从最简单的引导页导航,到轮转广告,到页面菜单等等,无不出现ViewPager的身影。应用广泛,简单好用,更好的交互性,这也是ViewPager一出现便大受程序员欢迎的原因。如此好用的控件,你是不是已经蠢蠢欲动了呢?不废话,我们将以项目为向导,由浅入深的讲解ViewPager,开始ViewPager的学习之旅吧。
2 什么时候可以使用ViewPager?
任何新的技术,最难的不是学习如何使用它,而是明白什么时候使用它最合适。正所谓物尽其用,只有正确的技术用在了正确的地方,那么才能发挥该技术最大的功效,做出好的应用。下面结合一些典型场景来让不了解ViewPager的你了解在什么情况下使用ViewPager才是最好的。ViewPager最典型的应用场景主要包括引导页导航,轮转广告,和页面菜单。可以这么说,但凡遇到界面切换的需求,都可以考虑ViewPager。抛砖引玉,剩下的就看读者发挥想象力了。
ViewPager的基本入门(和ListView对比学习)
那如何使用它呢,与ListView类似,我们也需要一个适配器,他就是PagerAdapter。ViewPager采用MVC模式将前段显示与后端数据进行分离,也就是说器装载数据并不是直接添加数据,而是,需要使用PagerAdapter。PagerAdapter相当于,MVC模式中的C(Controller,控制器),ViewPager相当MVC模式中的V(View,视图),为ViewPager提供的数据List,数组或者数据库,就相当于MVC中的M(Mode,模型)。
学习ViewPager不仅仅是学习ViewPager单一个控件那么简单,我们需要围绕MVC模式,把ViewPager用到的数据(M),视图(V),控制器(C)都理一遍,明白如何把他们,组合在一起,达到ViewPager的切换效果。
我们通过一个简单的项目来认识一下ViewPager的使用方式。
首先新建项目,引入ViewPager控件
ViewPager,它是google SDk中自带的一个附加包的一个类,可以用来实现屏幕间的切换,在V4包中。
准备视图 View
在主布局文件main.xml中添加ViewPager如下:
activity_main.xml
&RelativeLayout xmlns:android="/apk/res/android"
xmlns:tools="/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对应的组件,要将其放到想要滑动的位置,可以全屏显示,也可以半屏,任意大小,由程序员按需求控制。
准备数据模型 ,Mode
① 新建三个layout,用于滑动切换的视图:
我们的三个视图都非常简单,里面没有任何的控件,大家当然可以往里添加各种控件,但这里是个DEMO,只详解原理即可,所以我这里仅仅用背景来区别不用layout布局。
layout1.xml
&?xml version="1.0" encoding="utf-8"?&
&LinearLayout xmlns:android="/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ffffff"
android:orientation="vertical" &
&/LinearLayout&
layout2.xml
&?xml version="1.0" encoding="utf-8"?&
&LinearLayout xmlns:android="/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ffff00"
android:orientation="vertical" &
&/LinearLayout&
layout3.xml
&?xml version="1.0" encoding="utf-8"?&
&LinearLayout xmlns:android="/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ff00ff"
android:orientation="vertical" &
&/LinearLayout&
② 声明变量:
private View view1, view2, view3;
private List&View& viewL//view数组
private ViewPager viewP
//对应的viewPager
我们来看看上面的变量声明:
首先viewPager对应 &android.support.v4.view.ViewPager/&控件。
view1, view2, view3对应我们的三个layout,即layout1.xml,layout2.xml,layout3.xml
viewList是一个View数组,盛装上面的三个VIEW
数据的初始化:
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);
获取到找到ViewPager ,赋值给变量,最后将实例化的view1,view2,view3添加到viewList中。
准备控制器(Controller)—— PagerAdapter
PagerAdapter 是ViewPager的适配器。
适配器我们在ListView里面早就使用过,listView通过重写GetView()函数来获取当前要加载的Item。而PageAdapter不太相同,毕竟PageAdapter是单个VIew的合集。PagerAdapter在instantiateItem()里面给布局容器添加了将要显示的视图。
PageAdapter 必须重写的四个函数:
boolean isViewFromObject(View arg0, Object arg1)
int getCount()
void destroyItem(ViewGroup container, int position,Object object)
Object instantiateItem(ViewGroup container, int position)
下面,我们就看看四个主要方法改如何重写,都分别做了什么吧
public int getCount() {
// TODO Auto-generated method stub
return viewList.size();
getCount(),返回滑动的View的个数。
public void destroyItem(ViewGroup container, int position,
Object object) {
// TODO Auto-generated method stub
container.removeView(viewList.get(position));
destroyItem,从容器中删除指定position的View
public Object instantiateItem(ViewGroup container, int position) {
// TODO Auto-generated method stub
container.addView(viewList.get(position));
return viewList.get(position);
instantiateItem()方法中,我先讲指定position位置的View添加到容器中,末了,将本View返回。
public boolean isViewFromObject(View arg0, Object arg1) {
// TODO Auto-generated method stub
return arg0 == arg1;
这里为什么这么写暂不做讲解,知道这样写即可,后面我们会单独讲解清楚。
这么简单,我们就实现了三个view间的相互滑动。
第一个界面想第二个界面滑动
第二个界面想第三个界面滑动
以下是全部核心代码:
package com.example.testviewpage_1;
import java.util.ArrayL
import java.util.L
import java.util.zip.I
import android.app.A
import android.os.B
import android.support.v4.view.PagerA
import android.support.v4.view.ViewP
import android.view.LayoutI
import android.view.V
import android.view.ViewG
public class MainActivity extends Activity {
private View view1, view2, view3;
private ViewPager viewP
//对应的viewPager
private List&View& viewL//view数组
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() {
public boolean isViewFromObject(View arg0, Object arg1) {
// TODO Auto-generated method stub
return arg0 == arg1;
public int getCount() {
// TODO Auto-generated method stub
return viewList.size();
public void destroyItem(ViewGroup container, int position,
Object object) {
// TODO Auto-generated method stub
container.removeView(viewList.get(position));
public Object instantiateItem(ViewGroup container, int position) {
// TODO Auto-generated method stub
container.addView(viewList.get(position));
return viewList.get(position);
viewPager.setAdapter(pagerAdapter);
至此我们已经基本了解了ViewPager,学会了基本用法,接下来,我们就来详细学习ViewPager的核心PagerAdapter。
4 从PagerAdapter说开去——解读PagerAdapter的四大函数
4.1 且看官方文档怎么说?
最权威的讲解是官方文档,都是英文的,不好排版,我就不贴出来了,以下是我根据文档翻译出来的。有不明白的,可以自己看官方文档:
/reference/android/support/v4/view/PagerAdapter.html(加红)
安卓提供一个适配器用于填充ViewPager页面. 你很可能想要使用一个更加具体的实现, 例如:
FragmentPagerAdapter or FragmentStatePagerAdapter.
当你实现一个PagerAdapter时,至少需要覆盖以下几个方法:
instantiateItem(ViewGroup, int)
destroyItem(ViewGroup, int, Object)
getCount()
isViewFromObject(View, Object)
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方法。
上面的FragmentPagerAdapter 和FragmentStatePagerAdapter非常常用,我们放到后面来讲。
上面的话,重点只有两段:① ,②
针对上面两段,集中理解两点:
(1)第一段说明了,键(Key)的概念,首先这里要清楚的一点是,每个滑动页面都对应一个Key,而且这个Key值是用来唯一追踪这个页面的,也就是说每个滑动页面都与一个唯一的Key一一对应。大家先有这个概念就好,关于这个Key是怎么来的,下面再讲。
(2)当前page本身可以作为键,直接在destroyItem()返回,用来标示自己。下面,我们来讲讲Key
ViewPager的 key
destroyItem(ViewGroup, int, Object)
该方法把给定位置的界面丛容器中移除,负责从容器中删除视图,确保在finishUpdate(viewGroup)返回时视图能够被移除。
来看看我们前面的项目是怎么重写这个方法的:
public void destroyItem(ViewGroup container, int position,
Object object) {
// TODO Auto-generated method stub
container.removeView(viewList.get(position));
将给定位置的视图从container中移除了…… 这个方法必须被实现,而且不能调用父类,否则抛出异常。(说该方法没有被覆盖)
② getCount()
返回当前有效视图的个数。
public int getCount() {
// TODO Auto-generated method stub
return viewList.size();
返回了当前需要显示的视图的个数。
接下来的两个方法是重点。
③ instantiateItem(ViewGroup, int)
这个方法实现的功能是创建指定位置的视图,同时肩负着添加该创建的视图到指定容器container中,而这一步,要确保在finishUpdate(viewGroup)返回之后完成。
该方法返回一个代表该视图的键(key),没必要非是视图本身,也可以是这个页面的其他容器,我的理解是没必要视图本身,只要这个返回值能代表当前视图,并与视图一意对应即可,比如返回和该视图对应的position可以吗?(接下来我们做个例子试试)
给container添加一个视图。
返回代表该视图的Key
该方法和destroyItem(ViewGroup, int, Object)一样,在finishUpdate(ViewGroup)这句话执行完之后执行。
我们来看看我们是怎么做的:
public Object instantiateItem(ViewGroup container, int position) {
// TODO Auto-generated method stub
container.addView(viewList.get(position));
return viewList.get(position);
没有错,这里我们给container添加了一个View
viewList.get(position),,并将该视图作为key返回了。
回过头来,我们看看第四章的官方文档翻译:
② 对于非常简单的pageradapter或许你可以选择用page本身作为键,在创建并且添加到viewgroup后instantiateItem方法里返回该page本身即可
destroyItem将会将该page从viewgroup里面移除。isViewFromObject方法里面直接可以返回view == object。
就是这里,把当前的View作为key传出去,那么这个key在哪里被使用呢?就得来看看下面的方法了。
④ isViewFromObject(View, Object)
功能:该函数用来判断instantiateItem(ViewGroup, int)函数所返回来的Key与一个页面视图是否是代表的同一个视图(即它俩是否是对应的,对应的表示同一个View)
返回值:如果对应的是同一个View,返回True,否则返回False。
在上面的项目中,我们这样做的:
public boolean isViewFromObject(View arg0, Object arg1) {
// TODO Auto-generated method stub
return arg0 == arg1;
由于在instantiateItem()中,我们作为Key返回来的是当前的View,所以在这里判断时,我们直接将Key与View看是否相等来判断是否是同一个View。
发散思维:如果我们在instantiateItem()返回的是代表当前视图的position而非本身呢?这里该怎么做?接下来我们就解答你的疑问。
上面我们想必对key有个初步认识,下面我们举个例子来说明一下key和View的关系,由于key要和View一一对应,这里我把和View一一对应的position作为key返回,然后在上面的项目的基础上修改。这里只展示需要修改的代码。
我们更改了两个地方:
(1)instantiateItem()
public Object instantiateItem(ViewGroup container, int position) {
// TODO Auto-generated method stub
container.addView(viewList.get(position));
(2)2、isViewFromObject ()
public boolean isViewFromObject(View arg0, Object arg1) {
// TODO Auto-generated method stub
//根据传来的key(arg1),找到view,判断与传来的参数View arg0是不是同一个视图
return arg0 == viewList.get((int)Integer.parseInt(arg1.toString()));
判断instantiateItem()返回的key与视图是否对应,这里我们返回的是position,我们需要根据position找到对应的View,与传过来的View对比,看看是否对应。注意:这里,我们要先将obect对应转换为int类型:(int)Integer.parseInt(arg1.toString());然后再根据position找到对应的View;
5 ViewPager的进阶,添加标题栏
5.1 PagerTitleStrip
View可以添加标题栏,用来指示当前滑动到哪一页。先来一张效果图:
PagerTabStrip是ViewPager的一个关于当前页面、上一个页面和下一个页面的一个非交互的指示器。它经常作为ViewPager控件的一个子控件被被添加在XML布局文件中。在你的布局文件中,将它作为子控件添加在ViewPager中。而且要将它的 android:layout_gravity 属性设置为TOP或BOTTOM来将它显示在ViewPager的顶部或底部。每个页面的标题是通过适配器的getPageTitle(int)函数提供给ViewPager的。
主要是两点:
PagerTabStrip可以作为控件直接添加到xml布局文件中。
重写getPageTitle(int)来给PagerTabStrip提供标题。
你也许会发现上面只有上部分一部分的地方才有滑动切换,是因为我更改了布局文件。
先来看看布局文件:
&RelativeLayout xmlns:android="/apk/res/android"
xmlns:tools="/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.testviewpage_2.MainActivity" &
&android.support.v4.view.ViewPager
android:id="@+id/viewpager"
android:layout_width="wrap_content"
android:layout_height="200dip"
android:layout_gravity="center"&
&android.support.v4.view.PagerTitleStrip
android:id="@+id/pagertitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="top"
&/android.support.v4.view.ViewPager&
&/RelativeLayout&
这里将layout_height更改为200dip,只所以这么做,是为了告诉大家,只要在想要实现滑动切换的地方添加上&android.support.v4.view.ViewPager /&就可以实现切换,无所谓位置和大小,跟普通控件一样!!!!!!
重点是我们将PagerTabStrip作为子控件直接镶嵌在ViewPager中,设置layout_gravity="top" 或者 buttom。
重写适配器的getPageTitle()函数
在元项目基础上我们做了如下更改:
1、定义变量:
private List&String& titleL
//标题列表数组
申请了一个标题数组,来存储三个页面所对应的标题、
titleList = new ArrayList&String&();// 每个页面的Title数据
titleList.add("王鹏");
titleList.add("姜语");
titleList.add("结婚");
添加了标题数据
3、重写CharSequence getPageTitle(int )函数
public CharSequence getPageTitle(int position) {
// TODO Auto-generated method stub
return titleList.get(position);
根据位置返回当前所对应的标题。
5.2 PagerTabStrip
PagerTabStrip使用方法和上面类似。
先来看看效果:
效果和PagerTitleStrip差不多,但是有微小差别:
PagerTabStrip在当前页面下,标题的下方有一个横线作为导航。
PagerTabStrip的Tab是可以点击的,点击标题可以跳转到对应的页面。
PagerTabStrip是ViewPager的一个关于当前页面、上一个页面和下一个页面的一个可交互的指示器。它经常作为ViewPager控件的一个子控件被被添加在XML布局文件中。在你的布局文件中,将它作为子控件添加在ViewPager中。而且要将它的 android:layout_gravity 属性设置为TOP或BOTTOM来将它显示在ViewPager的顶部或底部。每个页面的标题是通过适配器的getPageTitle(int)函数提供给ViewPager的。
注意:可交互的,这就是PagerTabStrip和PagerTitleStrip最大的不一样。PagerTabStrip是可交互的,PagerTitleStrip是不可交互的。
用法与PagerTitleStrip完全相同,即:
1、首先,文中提到:在你的布局文件中,将它作为子控件添加在ViewPager中。
2、第二,标题的获取,是重写适配器的getPageTitle(int)函数来获取的。
看看实例:
1、XML布局
&RelativeLayout xmlns:android="/apk/res/android"
xmlns:tools="/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.testviewpage_2.MainActivity" &
&android.support.v4.view.ViewPager
android:id="@+id/viewpager"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"&
&android.support.v4.view.PagerTabStrip
android:id="@+id/pagertab"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="top"/&
&/android.support.v4.view.ViewPager&
&/RelativeLayout&
可以看到,同样,是将PagerTabStrip作为ViewPager的一个子控件直接插入其中,当然android:layout_gravity=""的值一样要设置为top或bottom。
2、重写适配器的getPageTitle()函数
代码里面不用改
public CharSequence getPageTitle(int position) {
// TODO Auto-generated method stub
return titleList.get(position);
根据位置返回当前所对应的标题。
Fragment 和 ViewPager的完美结合
—— FragmentPagerAdapter
前面讲解了ViewPager的普通实现方法,但android官方最推荐的一种实现方法却是使用fragment,Fragment的碎片化功能大大的丰富了ViewPager的功能和表现形式。先前我们实现ViewPager使用的是ViewPagerAdapter。而对于fragment,使用的是FragmentPagerAdapter和FragmentStatePagerAdapter。下面我们来学习一下。
FragmentPagerAdapter
FragmentPagerAdapter是PagerAdapter的子类,专门用来呈现fragment页面的,这些Fragment会一直保存在FragmentManager,以方便用户随时取用。
FragmentPagerAdapter适用于有限个fragment的页面管理,因为你所访问过的fragment都会保存在内存中。由于,fragment保存着大量的各种状态,这样就造成了比较大的内存开销。故,当遇到大量的页面切换的时候,建议采用FragmentStatePagerAdapter,这个我们会在下面的章节讲到。
FragmentPagerAdapter使用过程:
6.1.1 适配器的实现:
public class FragAdapter extends FragmentPagerAdapter {
private List&Fragment& mF
public FragAdapter(FragmentManager fm,List&Fragment& fragments) {
super(fm);
// TODO Auto-generated constructor stub
mFragments=
public Fragment getItem(int arg0) {
// TODO Auto-generated method stub
return mFragments.get(arg0);
public int getCount() {
// TODO Auto-generated method stub
return mFragments.size();
很简单吧,只需要继承FragmentPagerAdapter实现两个方法getItem(int arg)和 getCount(),就可以了。
这里,我们定义了一个fragment的List对象,在构造方法里面初始化了。如下
public FragAdapter(FragmentManager fm,List&Fragment& fragments) {
super(fm);
// TODO Auto-generated constructor stub
mFragments=
接下来我们实现了getCount(),和前面一样返回了页面的个数。这里我们返回了List对象的大小。List就是fragment的集合,有多少个fragment就展示多少个页面,这点很容易理解。如下:
public int getCount() {
// TODO Auto-generated method stub
return mFragments.size();
最后,根据传过来的键Key参数,返回该当前要显示的fragment,如下:
public Fragment getItem(int arg0) {
// TODO Auto-generated method stub
return mFragments.get(arg0);
构造Fragment类。
下面我们要分别构造3个Fragment,这里,我们第一个fragment1有一个可以点击的按钮,第二个和第三个fragment2,fragment3分别用不同的背景代替。
第一个Fragment类:
XML:(layout1.xml)
&?xml version="1.0" encoding="utf-8"?&
&LinearLayout xmlns:android="/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ffffff"
android:orientation="vertical" &
&Button android:id="@+id/fragment1_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="show toast"
&/LinearLayout&
Fragment1的java代码:
public class Fragment1 extends Fragment {
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// TODO Auto-generated method stub
View view= inflater.inflate(R.layout.layout1, container, false);
//对View中控件的操作方法
Button btn = (Button)view.findViewById(R.id.fragment1_btn);
btn.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// TODO Auto-generated method stub
Toast.makeText(getActivity(), "点击了第一个fragment的BTN", Toast.LENGTH_SHORT).show();
这里我加入了一个按钮,在onCreateView()方法里面加载了layout1,返回了要显示的View,同时,给按钮添加了一个监听事件,这里为了向读者说明利用了fragment我们可以实现各种各样的交互,ViewPager能做到的不仅仅是动态的图片,而是动态的交互。
第二个Fragment类:
XML代码:(layout2.xml)和上面的代码一样,没有做任何更改
&?xml version="1.0" encoding="utf-8"?&
&LinearLayout xmlns:android="/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ffff00"
android:orientation="vertical" &
&/LinearLayout&
java代码:
public class Fragment2 extends Fragment {
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// TODO Auto-generated method stub
View view=inflater.inflate(R.layout.layout2, container, false);
第三个Fragment类:
XML代码:(layout3.xml)同样,没做任何更改
&?xml version="1.0" encoding="utf-8"?&
&LinearLayout xmlns:android="/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ff00ff"
android:orientation="vertical" &
&/LinearLayout&
public class Fragment3 extends Fragment {
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// TODO Auto-generated method stub
View view=inflater.inflate(R.layout.layout3, container, false);
主Activity我继承了FragmentActivity,只有FragmentActivity内部才能内嵌Fragment普通Activity是不行的。
public class MainActivity extends FragmentActivity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//构造适配器
List&Fragment& fragments=new ArrayList&Fragment&();
fragments.add(new Fragment1());
fragments.add(new Fragment2());
fragments.add(new Fragment3());
FragAdapter adapter = new FragAdapter(getSupportFragmentManager(), fragments);
//设定适配器
ViewPager vp = (ViewPager)findViewById(R.id.viewpager);
vp.setAdapter(adapter);
很简单,我们构造了一个适配器,然后为ViewPager设置的适配器,和前面几乎一样。而适配器里面传入的,就是那三个我们准备好的fragment。
看看效果:
在第一个页面加一个按钮
第一页面向第二页面滑动
第二页面向第三个页面滑动
6.2 FragmentStatePagerAdapter
和FragmentPagerAdapter相比,它更适用于大量页面的展示,当整个fragment不再被访问,则会被销毁(由于预加载,默认最多保存3个fragment),只保存其状态,这相对于FragmentPagerAdapter占有了更少的内存,为什么大量页面用FragmentStatePagerAdapter?不言而喻了吧。
FragmentStatePagerAdapter的用法和FragmentPagerAdapter一样,这里就不再赘述。
在初次使用的FragmentPagerAdapter的时候,曾爆出类型转换的异常。这是为什么呢?跟踪代码才发现出错的地方发生在fragments.add(new Fragment1()); 错误提示无法将Fragment1(Fragment的子类)强制转换成Fragment,当时真是莫名其妙,明明Fragment1就是Fragment,为什么说不是呢?经过仔细排查才发现在Fragment1里面导入的是android.app.Fragment,而在Activity类导入的是为android.support.v4.app.Fragment。统一导入之后才消除异常,不细心造成的错误往往难以排查,让人纠结,这里我们在使用FragmentPagerAdapter必须注意导入正确的包android.support.v4.app.Fragment。
ViewPager的预加载机制。
ViewPager能够如此流畅的切换页面得益于其预加载的机制,那么什么是ViewPager的预加载呢?
归纳掌握两点:
ViewPager会预先加载左右两边的图片,预加载的个数最多3个。前方超出当个数由4个的时候,最前方的会被销毁。预加载和销毁分别回调以下两个方法:
instantiateItem(ViewGroup, int)
destroyItem(ViewGroup, int, Object)
限制:当左边图片的position小于0的时候,不会预加载;
当右边的图片的position大于或者等于item总数的时候,也不会预加载。
我画了一张示意图:如下左边0位置的被销毁
8 学以致用,用ViewPager做个选项卡。
至此,我们已经基本学完了ViewPager的常用特性。学贵于致用,接下来我们通过一个涵盖面全的例子,来把我们所学的知识用一遍。
做一个选项卡效果,我们立刻想到ViewPagerIndicator,利用我们以上学过的知识,就可以轻易实现这个功能。
先来一张效果图,激发激发热血吧:
上图 左右滑动,或者点击文字,界面会切换,同时,页卡文字下方的滑块也会滑动,指示当前显示的页面。
回忆一下,我们在使用ViewPagerIndicator的时候,会在ViewPager的上面添加ViewPagerIndicator,然后通过ViewPagerIndicator的setViewPager(ViewPager mPager)设置ViewPager,使得ViewPagerIndicator指示器与ViewPager相关联。
这里,我们用一个包含几个 TextView的LinearLayout,下边一个ImageView 替换,如下:
&?xml version="1.0" encoding="utf-8"?&
&LinearLayout xmlns:android="/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" &
&LinearLayout
android:id="@+id/linearLayout1"
android:layout_width="fill_parent"
android:layout_height="60dip"
android:background="#FFFFFF" &
android:id="@+id/text1"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1.0"
android:gravity="center"
android:text="页卡1"
android:textColor="#000000"
android:textSize="22.0dip" /&
android:id="@+id/text2"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1.0"
android:gravity="center"
android:text="页卡2"
android:textColor="#000000"
android:textSize="22.0dip" /&
android:id="@+id/text3"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1.0"
android:gravity="center"
android:text="页卡3"
android:textColor="#000000"
android:textSize="22.0dip" /&
&/LinearLayout&
&ImageView
android:id="@+id/cursor"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:scaleType="matrix"
android:src="@drawable/a" /&
&android.support.v4.view.ViewPager
android:id="@+id/vPager"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="1.0"
android:background="#000000"
android:flipInterval="30"
android:persistentDrawingCache="animation" /&
&/LinearLayout&
下面是ViewPager。
接下来准备3个切换的布局:(3个布局都是一个RelativeLayout,只是,背景颜色不同而已)
fragment_main_1.xml,fragment_main_2.xml,fragment_main_3.xml
fragment_main_1.xml:
&RelativeLayout xmlns:android="/apk/res/android"
xmlns:tools="/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#000000" &
&/RelativeLayout&
fragment_main_2.xml:
&RelativeLayout xmlns:android="/apk/res/android"
xmlns:tools="/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ffffff" &
&/RelativeLayout&
fragment_main_3.xml:
&RelativeLayout xmlns:android="/apk/res/android"
xmlns:tools="/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ff0000" &
&/RelativeLayout&
下面由浅入深,一步步把功能做完:
先完成ViewPager界面切换,和3 基本入门那一章节一致。
初始化 ViewPager布局
private void initViewPager() {
vPager = (ViewPager) findViewById(R.id.vPager);
List&View& listViews = new ArrayList&View&();
listViews.add(View.inflate(this, R.layout.fragment_main_1, null));
listViews.add(View.inflate(this, R.layout.fragment_main_2, null));
listViews.add(View.inflate(this, R.layout.fragment_main_3, null));
MyPagerAdapter adapter = new MyPagerAdapter(listViews);
vPager.setAdapter(adapter);
// 给ViewPager设置监听
MyOnPagerChangeListener listener = new MyOnPagerChangeListener();
vPager.setOnPageChangeListener(listener);
这一部分相信大家很熟悉了,无非做了2步:
(1)给ViewPager设置适配器。(加载了3个我们已经准备好的布局)
(2)给ViewPager设置滑动页面监听。
在此就不再多讲,下面是适配器的实现:
class MyPagerAdapter extends PagerAdapter{
List&View& listV
public MyPagerAdapter(List&View& listViews) {
this.listViews = listV
public int getCount() {
// TODO Auto-generated method stub
return listViews.size();
public boolean isViewFromObject(View arg0, Object arg1) {
// TODO Auto-generated method stub
return arg0 == arg1;
public Object instantiateItem(View container, int position) {
// TODO Auto-generated method stub
((ViewPager)container).addView(listViews.get(position));
return listViews.get(position);
public void destroyItem(View container, int position, Object object) {
((ViewPager)container).removeView(listViews.get(position));
至此,我们已经可以切换界面了。可是,我们发现选项卡下面的指示滑动条并不能随着页面的切换而移动,从而标识当前页面。这就是我们下一步要做的。
这里,我们完成指示滑动条的移动。
通过对ViewPager页面切换的监听,用唯一动画相应的距离实现标识滑块的移动。
滑块相关数据初始化
这一段是很重要的,先贴出核心代码,随后详细讲解。
private void initImageView() {
cursor = (ImageView) findViewById(R.id.cursor);
bmpw = BitmapFactory.decodeResource(getResources(), R.drawable.a).getWidth(); //滑块的宽度
DisplayMetrics dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
//给DisplayMetrics赋值
screenW = dm.widthP
offset = (screenW/3 - bmpw)/2;
//滑块动画初始位置
//设置动画初始位置
Matrix matrix = new Matrix();
matrix.postTranslate(offset, 0);
cursor.setImageMatrix(matrix);
通过上面的代码主要做了这几个事儿:
cursor = (ImageView) findViewById(R.id.cursor);
//滑块的宽度
bmpw = BitmapFactory.decodeResource(getResources(), R.drawable.a).getWidth();
加载了滑块,获得了滑块的宽度。
(2)获得了屏幕的宽度
DisplayMetrics dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
//给DisplayMetrics赋值
screenW = dm.widthP
//获得屏幕宽度
上面的代码通过一个类WindowManager获得屏幕的相关信息,保存在
DisplayMetrics 对象里面,然后获取其屏幕宽度。
(3)计算滑块的初始位置
offset = (screenW/3 - bmpw)/2;
//滑块动画初始位置
滑块的初始位置的计算,请看如下示意图
//设置动画初始位置
Matrix matrix = new Matrix();
matrix.postTranslate(offset, 0);
cursor.setImageMatrix(matrix);
这段代码做的事情也很简单,给滑块设置了初始位置,即当选项页面为第0页的时候滑块的位置。这里是通过Matrix 对象来设置滑块的位置信息。
实现页面监听类的方法
class MyOnPagerChangeListener implements OnPageChangeListener{
int one = offset * 2 +
//选项卡0 -& 1 的偏移量
int two = one * 2;
// //选项卡1 -& 2 的偏移量
public void onPageScrollStateChanged(int arg0) {
// TODO Auto-generated method stub
public void onPageScrolled(int arg0, float arg1, int arg2) {
// TODO Auto-generated method stub
public void onPageSelected(int position) {
animation = null;
Toast.makeText(MainActivity.this, "position:"+position, Toast.LENGTH_SHORT).show();
Log.i("hql--&", "one=="+one+"
two=="+two);
Log.i("hql--&", "offset=="+offset+"
bmpw=="+bmpw+"screenW"+screenW);
switch (position) {
if(currentIndex == 1){
animation = new TranslateAnimation(one, 0, 0, 0);
}else if(currentIndex == 2){
animation = new TranslateAnimation(two, 0, 0, 0);
if(currentIndex == 0){
animation = new TranslateAnimation(offset, one, 0, 0);
}else if(currentIndex == 2){
animation = new TranslateAnimation(two, one, 0, 0);
if(currentIndex == 0){
animation = new TranslateAnimation(offset, two, 0, 0);
}else if(currentIndex == 1){
animation = new TranslateAnimation(one, two, 0, 0);
currentIndex =
//记录当前的页面号
animation.setDuration(300);
//设置动画时间
animation.setFillAfter(true);
//设置停留在动画后
cursor.startAnimation(animation);
上面主要做了两件事:
计算由第0页到第1页,滑块移动的距离。
int one = offset * 2 +
//选项卡0 -& 1 的偏移量
int two = one * 2;
// //选项卡1 -& 2 的偏移量
计算方法无非就是数学题,我画了张示意图。
实现onPageSelected(int Position)方法
public void onPageSelected(int position) {
animation = null;
Toast.makeText(MainActivity.this, "position:"+position, Toast.LENGTH_SHORT).show();
Log.i("hql--&", "one=="+one+"
two=="+two);
Log.i("hql--&", "offset=="+offset+"
bmpw=="+bmpw+"screenW"+screenW);
switch (position) {
if(currentIndex == 1){
animation = new TranslateAnimation(one, 0, 0, 0);
}else if(currentIndex == 2){
animation = new TranslateAnimation(two, 0, 0, 0);
if(currentIndex == 0){
animation = new TranslateAnimation(offset, one, 0, 0);
}else if(currentIndex == 2){
animation = new TranslateAnimation(two, one, 0, 0);
if(currentIndex == 0){
animation = new TranslateAnimation(offset, two, 0, 0);
}else if(currentIndex == 1){
animation = new TranslateAnimation(one, two, 0, 0);
currentIndex =
//记录当前的页面号
animation.setDuration(300);
//设置动画时间
animation.setFillAfter(true);
//设置停留在动画后
cursor.startAnimation(animation);
通过该方法,我们可以很清晰的看到,这个方法里根据传入的代表当前页面的键,这里是Position,来在滑动的时候使滑块做相应的移动。
做完这一步,我们的滑块已经可以随着页面切换而移动起来了。
为了更好的交互,完成点击选项卡切换页面。
思路:给3个选项卡(这里是3个TextView)设置点击事件,在点击事件里面通过ViewPager.setCurrentItem(int num)设置当前页面的键(KEY).
private void initTextView() {
TextView text1 = (TextView) findViewById(R.id.text1);
TextView text2 = (TextView) findViewById(R.id.text2);
TextView text3 = (TextView) findViewById(R.id.text3);
text1.setOnClickListener(this);
text2.setOnClickListener(this);
text3.setOnClickListener(this);
初始化选项卡文字,这些文字做成控件的时候可以设置,同时给他们设置监听。
处理点击事件:
public void onClick(View v) {
switch (v.getId()) {
case R.id.text1:
vPager.setCurrentItem(0);
case R.id.text2:
vPager.setCurrentItem(1);
case R.id.text3:
vPager.setCurrentItem(2);
代码很简单,至此,点击选项卡也可以实现页面切换,实现了双向互动。
这里我再把变量申明和OnCreate()方法里面的调用代码贴出。
private int
//滑块动画初始位置
private int
//滑块的宽度
private int currentIndex = 0;
//默认当前也卡号为0
private ImageV
private int screenW;
//屏幕宽度
private ViewPager vP
//ViewPager
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initImageView();
//初始化滑块
initTextView();
//初始化文字
initViewPager();
//初始化ViewPager布局
好了,一个双向互动的选项卡就完成了,怎么样,是不是很简单?其实ViewPagerIndicator实现的思路和我们做的选项卡差不多,亲爱读者们,花点时间把这个Demo封装一下,提供一些方便的设置方法,比如设置任意长度的title,就是一个精简的选显卡控件了。
由此我们可以逆推,当然我们要掌握一个开源的控件时并不难,都是由使用到熟悉。通常都是在布局里面引用该控件,然后在java代码通过findViewById()方法找到该空间,之后通过该控件的一些方法,设置相应参数即可使用。当然,熟悉的基础上,下一步,就是深入了解,毕竟市面上的开源控件再怎么样都是人写的,那就很可能不是你想当然那样,所以通过一些方法去了解开源控件很重要。我了解一个控件的特性一般先阅读说明,然后通过调试,打log日志和假设验证的方式,来了解一个控件,这些方式都很普通,也很简单,却多用几次就得心应手了,但是却很实用,重要的是要有求真精神。
一路来,从认识到灵活运用,由浅入深,我们好像挺顺利,其实不然,一个好的应用都是从bug中产出的,好的程序也是错误中不断优化出来。我们在计算滑块的移动距离的时候,会发生计算结果为0的情况:如下
int one = offset * 2 +
//选项卡0 -& 1 的偏移量
int two = one * 2;
// //选项卡1 -& 2 的偏移量
这是为什么呢?
经过代码跟踪,最后才发现我们先初始化ViewPager的监听类,在初始化ViewPager的过程中,我们计算了移动的偏移量,滑块动画初始位置offset 和screenW都是还没有初始化,都是0,此时我们再计算滑块长度和初始值,导致移动距离one和two都为0.所以当我们遇到问题,调试是一个很好的办法。
如果您想提高自己的技术水平,认识同行朋友、开拓技术视野,请加入QQ群:
Powered by
& 2014 &&&联系本站:}

我要回帖

更多关于 viewpager和activity 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信