Android使用Fragment来实现ViewPager的功能(解决切换Fragment状态不保存)以及各个Fragment之间的通信
以下内容为原创,转载请注明:http://www.cnblogs.com/tiantianbyconan/p/3364728.html
我前两天写过一篇博客《Android使用Fragment来实现TabHost的功能(解决切换Fragment状态不保存)以及各个Fragment之间的通信》(http://www.cnblogs.com/tiantianbyconan/p/3360938.html),实现了Tab切换时保留当前Fragment状态,并在切换前自动回调onPause()方法,在切换后自动调用onResume(),这样就做到了跟TahHost一样的功能。
今天来实现下ViewPager的功能,google提供了一个FragmentPagerAdapter这么一个适配器,蛋疼的是,碰到了跟上次类似的问题。比如ViewPager有5个page,刚打开的时候,会加载page1和page2,我们手动切换到page2的时候,会加载page3,切换到page3的时候,加载page4的同时会destory掉page1,所以,还是面临同样的问题,page的状态无法保存,于是,咱还是自己来实现下好了,自己动手,丰衣足食嘛!(同样 有朋友知道解决办法的话,希望联系我,赐教下哈)
先来看下整个demo的结构,跟上次实现TabHost的例子差不多:

TabAFm到TabEFm都是Fragment,并且每个Fragment对应一个布局文件。
TabAFm.java:
package com.wangjie.fragmentviewpagertest; import android.app.Activity;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup; /**
* Created with IntelliJ IDEA.
* Author: wangjie email:tiantian.china.2@gmail.com
* Date: 13-6-14
* Time: 下午2:39
*/
public class TabAFm extends Fragment{
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
System.out.println("AAAAAAAAAA____onAttach");
} @Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
System.out.println("AAAAAAAAAA____onCreate");
} @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
System.out.println("AAAAAAAAAA____onCreateView");
return inflater.inflate(R.layout.tab_a, container, false);
} @Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
System.out.println("AAAAAAAAAA____onActivityCreated");
} @Override
public void onStart() {
super.onStart();
System.out.println("AAAAAAAAAA____onStart");
} @Override
public void onResume() {
super.onResume();
System.out.println("AAAAAAAAAA____onResume");
} @Override
public void onPause() {
super.onPause();
System.out.println("AAAAAAAAAA____onPause");
} @Override
public void onStop() {
super.onStop();
System.out.println("AAAAAAAAAA____onStop");
} @Override
public void onDestroyView() {
super.onDestroyView();
System.out.println("AAAAAAAAAA____onDestroyView");
} @Override
public void onDestroy() {
super.onDestroy();
System.out.println("AAAAAAAAAA____onDestroy");
} @Override
public void onDetach() {
super.onDetach();
System.out.println("AAAAAAAAAA____onDetach");
}
}
如上述代码所示,TabAFm是一个Fragment,对应的布局文件是tab_a.xml,并实现了他的所有的生命周期回调函数并打印,便于调试
tab_a.xml布局中有个EditText
其他的Fragment大同小异,这里就不贴出代码了
现在来看MainActivity:
package com.wangjie.fragmentviewpagertest; import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.view.ViewPager; import java.util.ArrayList;
import java.util.List; public class MainActivity extends FragmentActivity {
private ViewPager viewPager;
public List<Fragment> fragments = new ArrayList<Fragment>();
public String hello = "hello "; @Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main); fragments.add(new TabAFm());
fragments.add(new TabBFm());
fragments.add(new TabCFm());
fragments.add(new TabDFm());
fragments.add(new TabEFm()); viewPager = (ViewPager) findViewById(R.id.viewPager);
FragmentViewPagerAdapter adapter = new FragmentViewPagerAdapter(this.getSupportFragmentManager(), viewPager,fragments);
adapter.setOnExtraPageChangeListener(new FragmentViewPagerAdapter.OnExtraPageChangeListener(){
@Override
public void onExtraPageSelected(int i) {
System.out.println("Extra...i: " + i);
}
}); } }
MainActivity上述代码所示
MainActivity是包含Fragment的Activity(也就是这里的5个Fragment)
他继承了FragmentActivity(因为我这里用的是android-support-v4.jar)
用一个List<Fragment>去维护5个Fragment,也就是5个page。
MainActivity的布局很简单,就一个ViewPager,main.xml如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<android.support.v4.view.ViewPager
android:id="@+id/viewPager"
android:layout_width="match_parent"
android:layout_height="match_parent"
/> </LinearLayout>
现在回到MainActivity中,下面这个FragmentViewPagerAdapter类是关键,是我自己编写的用于绑定和处理fragments和ViewPager之间的逻辑关系
FragmentViewPagerAdapter adapter = new FragmentViewPagerAdapter(this.getSupportFragmentManager(), viewPager,fragments);
现在看下FragmentViewPagerAdapter:
package com.wangjie.fragmentviewpagertest; import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.view.View;
import android.view.ViewGroup; import java.util.List; /**
* 为ViewPager添加布局(Fragment),绑定和处理fragments和viewpager之间的逻辑关系
*
* Created with IntelliJ IDEA.
* Author: wangjie email:tiantian.china.2@gmail.com
* Date: 13-10-11
* Time: 下午3:03
*/
public class FragmentViewPagerAdapter extends PagerAdapter implements ViewPager.OnPageChangeListener{
private List<Fragment> fragments; // 每个Fragment对应一个Page
private FragmentManager fragmentManager;
private ViewPager viewPager; // viewPager对象
private int currentPageIndex = 0; // 当前page索引(切换之前) private OnExtraPageChangeListener onExtraPageChangeListener; // ViewPager切换页面时的额外功能添加接口 public FragmentViewPagerAdapter(FragmentManager fragmentManager, ViewPager viewPager , List<Fragment> fragments) {
this.fragments = fragments;
this.fragmentManager = fragmentManager;
this.viewPager = viewPager;
this.viewPager.setAdapter(this);
this.viewPager.setOnPageChangeListener(this);
} @Override
public int getCount() {
return fragments.size();
} @Override
public boolean isViewFromObject(View view, Object o) {
return view == o;
} @Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView(fragments.get(position).getView()); // 移出viewpager两边之外的page布局
} @Override
public Object instantiateItem(ViewGroup container, int position) {
Fragment fragment = fragments.get(position);
if(!fragment.isAdded()){ // 如果fragment还没有added
FragmentTransaction ft = fragmentManager.beginTransaction();
ft.add(fragment, fragment.getClass().getSimpleName());
ft.commit();
/**
* 在用FragmentTransaction.commit()方法提交FragmentTransaction对象后
* 会在进程的主线程中,用异步的方式来执行。
* 如果想要立即执行这个等待中的操作,就要调用这个方法(只能在主线程中调用)。
* 要注意的是,所有的回调和相关的行为都会在这个调用中被执行完成,因此要仔细确认这个方法的调用位置。
*/
fragmentManager.executePendingTransactions();
} if(fragment.getView().getParent() == null){
container.addView(fragment.getView()); // 为viewpager增加布局
} return fragment.getView();
} /**
* 当前page索引(切换之前)
* @return
*/
public int getCurrentPageIndex() {
return currentPageIndex;
} public OnExtraPageChangeListener getOnExtraPageChangeListener() {
return onExtraPageChangeListener;
} /**
* 设置页面切换额外功能监听器
* @param onExtraPageChangeListener
*/
public void setOnExtraPageChangeListener(OnExtraPageChangeListener onExtraPageChangeListener) {
this.onExtraPageChangeListener = onExtraPageChangeListener;
} @Override
public void onPageScrolled(int i, float v, int i2) {
if(null != onExtraPageChangeListener){ // 如果设置了额外功能接口
onExtraPageChangeListener.onExtraPageScrolled(i, v, i2);
}
} @Override
public void onPageSelected(int i) {
fragments.get(currentPageIndex).onPause(); // 调用切换前Fargment的onPause()
// fragments.get(currentPageIndex).onStop(); // 调用切换前Fargment的onStop()
if(fragments.get(i).isAdded()){
// fragments.get(i).onStart(); // 调用切换后Fargment的onStart()
fragments.get(i).onResume(); // 调用切换后Fargment的onResume()
}
currentPageIndex = i; if(null != onExtraPageChangeListener){ // 如果设置了额外功能接口
onExtraPageChangeListener.onExtraPageSelected(i);
} } @Override
public void onPageScrollStateChanged(int i) {
if(null != onExtraPageChangeListener){ // 如果设置了额外功能接口
onExtraPageChangeListener.onExtraPageScrollStateChanged(i);
}
} /**
* page切换额外功能接口
*/
static class OnExtraPageChangeListener{
public void onExtraPageScrolled(int i, float v, int i2){}
public void onExtraPageSelected(int i){}
public void onExtraPageScrollStateChanged(int i){}
} }
这里解决Fragment切换重新加载布局的办法,用的是把几个Fragment全部Add,然后根据要显示的哪个Fragment就把哪个Fragment的View给添加到“ViewGroup container”上去。
效果输出:
// 以下打开程序后,加载PageA和PageB
10-12 09:42:46.671: INFO/System.out(27248): AAAAAAAAAA____onAttach
10-12 09:42:46.671: INFO/System.out(27248): AAAAAAAAAA____onCreate
10-12 09:42:46.671: INFO/System.out(27248): AAAAAAAAAA____onCreateView
10-12 09:42:46.761: INFO/System.out(27248): AAAAAAAAAA____onActivityCreated
10-12 09:42:46.765: INFO/System.out(27248): AAAAAAAAAA____onStart
10-12 09:42:46.765: INFO/System.out(27248): AAAAAAAAAA____onResume
10-12 09:42:46.847: INFO/System.out(27248): BBBBBBBBBBB____onAttach
10-12 09:42:46.847: INFO/System.out(27248): BBBBBBBBBBB____onCreate
10-12 09:42:46.851: INFO/System.out(27248): BBBBBBBBBBB____onCreateView
10-12 09:42:46.867: INFO/System.out(27248): BBBBBBBBBBB____onActivityCreated
10-12 09:42:46.867: INFO/System.out(27248): BBBBBBBBBBB____onStart
10-12 09:42:46.867: INFO/System.out(27248): BBBBBBBBBBB____onResume
// 以下切换到PageB
10-12 09:42:57.285: INFO/System.out(27248): AAAAAAAAAA____onPause // 切换到PageB前会调用PageA的onPause()方法
10-12 09:42:57.285: INFO/System.out(27248): BBBBBBBBBBB____onResume // 切换到PageB后会调用PageB的onResume()方法
10-12 09:42:57.285: INFO/System.out(27248): Extra...i: 1 // 切换页面时会调用切换额外功能接口(用户可以自己写需要的逻辑)
10-12 09:42:57.582: INFO/System.out(27248): CCCCCCCCCC____onAttach // 切换到PageB后会加载PageC
10-12 09:42:57.586: INFO/System.out(27248): CCCCCCCCCC____onCreate
10-12 09:42:57.586: INFO/System.out(27248): CCCCCCCCCC____onCreateView
10-12 09:42:57.675: INFO/System.out(27248): CCCCCCCCCC____onActivityCreated
10-12 09:42:57.675: INFO/System.out(27248): CCCCCCCCCC____onStart
10-12 09:42:57.675: INFO/System.out(27248): CCCCCCCCCC____onResume
// 以下切换到PageC
10-12 09:43:18.261: INFO/System.out(27248): BBBBBBBBBBB____onPause // 切换到PageC前会调用PageB的onPause()方法
10-12 09:43:18.261: INFO/System.out(27248): CCCCCCCCCC____onResume // 切换到PageC后会调用PageC的onResume()方法
10-12 09:43:18.261: INFO/System.out(27248): Extra...i: 2 // 切换页面时会调用切换额外功能接口(用户可以自己写需要的逻辑)
10-12 09:43:18.726: INFO/System.out(27248): DDDDDDDDD____onAttach // 切换到PageC后会加载PageD
10-12 09:43:18.726: INFO/System.out(27248): DDDDDDDDD____onCreate
10-12 09:43:18.726: INFO/System.out(27248): DDDDDDDDD____onCreateView
10-12 09:43:18.738: INFO/System.out(27248): DDDDDDDDD____onActivityCreated
10-12 09:43:18.738: INFO/System.out(27248): DDDDDDDDD____onStart
10-12 09:43:18.742: INFO/System.out(27248): DDDDDDDDD____onResume
// 以下切换到PageB
10-12 09:43:20.742: INFO/System.out(27248): CCCCCCCCCC____onPause // 切换到PageB前会调用PageC的onPause()方法
10-12 09:43:20.742: INFO/System.out(27248): BBBBBBBBBBB____onResume // 切换到PageB后会调用PageB的onResume()方法
10-12 09:43:20.746: INFO/System.out(27248): Extra...i: 1 // 切换页面时会调用切换额外功能接口(用户可以自己写需要的逻辑)
好了,到此为止,我们已经用Fragment实现了ViewPager的功能了,同样,下面来看下各个Fragment之间的通信
现在的情况是TabAFm中有个EditText,TabBFm中有个Button,MainActivity中有个变量“hello”
要做的是,切换到A,输入“I'm PageA”,切换到B,点击Button后,Toast显示“hello I'm PageA”
MainActivity中没什么好说的,就一个hello变量:
public String hello = "hello ";
TabBFm中:
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
System.out.println("BBBBBBBBBBB____onActivityCreated");
this.getView().findViewById(R.id.clickme).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
// 获得绑定的FragmentActivity
MainActivity activity = ((MainActivity)getActivity());
// 获得TabAFm的控件
EditText editText = (EditText) activity.fragments.get(0).getView().findViewById(R.id.edit); Toast.makeText(activity, activity.hello + editText.getText(), Toast.LENGTH_SHORT).show();
}
});
}
最终效果图:

demo下载:http://pan.baidu.com/s/1stGQ7
Android使用Fragment来实现ViewPager的功能(解决切换Fragment状态不保存)以及各个Fragment之间的通信的更多相关文章
- Android学习笔记:使用ViewPager组件实现图片切换
在很多App中,尤其是第一次安装启动后,都会出现几个图片进行一些app的介绍和说明,图片可以随着滑动而切换. 我们这里利用 ViewPager组件来演示如何实现这一点. 1.创建一个app工程,默认创 ...
- Android之ActionBar、Tabs、Fragment、ViewPager实现标签页切换并缓存页面
感觉 Android 到处都是坑,每个地方都要把人折腾半天. 今天来简单说说 Android之ActionBar.Tabs.Fragment.ViewPager 实现标签页切换并缓存页面 关于他们的介 ...
- Android使用Fragment来实现TabHost的功能(解决切换Fragment状态不保存)以及各个Fragment之间的通信
以下内容为原创,转载请注明:http://www.cnblogs.com/tiantianbyconan/p/3360938.html 如新浪微博下面的标签切换功能,我以前也写过一篇博文(http:/ ...
- [Android Pro] fragment中嵌套viewpager,vierpager中有多个fragment,不显示
referece to : http://blog.csdn.net/mybook1122/article/details/24003343 现在好多应用流行一种布局.底部几个工具栏选项,上面也有类 ...
- Android使用Fragment来实现TabHost的功能
http://www.cnblogs.com/tiantianbyconan/p/3360938.html 好了,到此为止,我们已经用Fragment实现了类似TabHost的功能了,下面来看下各个F ...
- 类似掌盟的Tab页 Android 开源框架ViewPageIndicator 和 ViewPager 仿网易新闻客户端Tab标签 (转)
原博客地址 :http://blog.csdn.net/xiaanming/article/details/10766053 本文转载,记录学习用,如有需要,请到原作者网站查看(上面这个网址) 之前 ...
- Android 开源框架ActionBarSherlock 和 ViewPager 仿网易新闻客户端
转载请注明出处:http://blog.csdn.net/xiaanming/article/details/9971721 大家都知道Android的ActionBar是在3.0以上才有的,那么在3 ...
- 解决Fragment中使用ViewPager时,ViewPager里的Fragment错位和空白问题
这两天开始在改OSChina的开源android客户端,打算用Fragment来分离Main这个Activity里的功能.用Fragment嵌套ViewPager+Fragment的时候发现问题. 红 ...
- Android 开源框架ViewPageIndicator 和 ViewPager 仿网易新闻clientTab标签
之前用JakeWharton的开源框架ActionBarSherlock和ViewPager实现了对网易新闻clientTab标签的功能,ActionBarSherlock是在3.0下面的机器支持Ac ...
随机推荐
- REST API出错响应的设计
REST API应用很多,一方面提供公共API的平台越来越多,比如微博.微信等:一方面移动应用盛行,为Web端.Android端.IOS端.PC端,搭建一个统一的后台,以REST API的形式提供服务 ...
- Microsoft Azure News(2) 在Microsoft Azure上运行SAP应用程序
<Windows Azure Platform 系列文章目录> 2014年6月27日消息,在 Microsoft Azure 上提供 SAP Business Suite 软件.All-I ...
- apache(nginx)+django+virutalenv(virtualenvwrapper)+gunicorn+supervisor配置高效web环境
前言 django的调试模式配置简单,用于测试十分方便,但众所周知,这个只适合于调试,生产上运行效率十分低下. 后来考虑用nginx+uwsgi的模式进行,但之前配置过apache+wsgi的方式,感 ...
- EDNS
随着业务的复杂化和多样化,RFC1035中定义的DNS消息格式和它支持的消息内容已经不足以满足一些DNS服务器的需求,于是,RFC2671中提出了一种扩展DNS机制EDNS(Extension Mec ...
- ASP.NET MVC ValueProvider小结
在Model绑定中,Model的数据来源有很多种,在MVC里面则定义了一套ValueProvider的组件来处理Model数据来源多样性的问题,ValueProvider整个结构类似于字典(Dictr ...
- Calling startActivity() from outside of an Activity
在Activity中使用startActivity()方法不会有任何限制,因为Activity重载了Context的startActivity()方法.但是如果是在其他地方(如Widget或Servi ...
- hibernate简单注释(一.1)
**************************************************************************************************** ...
- RecyclerView和PullToRefreshListView的对比
项目中上拉刷新和下拉加载一直都是比较常见的:以前一般都是重写ListView或直接用PullToRefreshListView的框架:最近尝试用RecyclerView来实现下拉加载上拉刷新也是不错的 ...
- pageEncoding的默认设置
windows-->preference-->myeclipse-->files and editors-->jsp 右侧 Encoding 选择 ISO 10646/Uni ...
- 如何在MFC对话框应用程序中使用ColorPicker控件
在日常的应用程序开发中,当涉及到曲线绘制时,为了将多条不同类型的曲线区分开,常常需要将它们指定不同的颜色.今天在这里简单的记录一下,如何实现及使用ColorPicker控件.程序用到4个文件依次为:C ...