以下内容为原创,转载请注明: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之间的通信的更多相关文章

  1. Android学习笔记:使用ViewPager组件实现图片切换

    在很多App中,尤其是第一次安装启动后,都会出现几个图片进行一些app的介绍和说明,图片可以随着滑动而切换. 我们这里利用 ViewPager组件来演示如何实现这一点. 1.创建一个app工程,默认创 ...

  2. Android之ActionBar、Tabs、Fragment、ViewPager实现标签页切换并缓存页面

    感觉 Android 到处都是坑,每个地方都要把人折腾半天. 今天来简单说说 Android之ActionBar.Tabs.Fragment.ViewPager 实现标签页切换并缓存页面 关于他们的介 ...

  3. Android使用Fragment来实现TabHost的功能(解决切换Fragment状态不保存)以及各个Fragment之间的通信

    以下内容为原创,转载请注明:http://www.cnblogs.com/tiantianbyconan/p/3360938.html 如新浪微博下面的标签切换功能,我以前也写过一篇博文(http:/ ...

  4. [Android Pro] fragment中嵌套viewpager,vierpager中有多个fragment,不显示

    referece to :  http://blog.csdn.net/mybook1122/article/details/24003343 现在好多应用流行一种布局.底部几个工具栏选项,上面也有类 ...

  5. Android使用Fragment来实现TabHost的功能

    http://www.cnblogs.com/tiantianbyconan/p/3360938.html 好了,到此为止,我们已经用Fragment实现了类似TabHost的功能了,下面来看下各个F ...

  6. 类似掌盟的Tab页 Android 开源框架ViewPageIndicator 和 ViewPager 仿网易新闻客户端Tab标签 (转)

    原博客地址  :http://blog.csdn.net/xiaanming/article/details/10766053 本文转载,记录学习用,如有需要,请到原作者网站查看(上面这个网址) 之前 ...

  7. Android 开源框架ActionBarSherlock 和 ViewPager 仿网易新闻客户端

    转载请注明出处:http://blog.csdn.net/xiaanming/article/details/9971721 大家都知道Android的ActionBar是在3.0以上才有的,那么在3 ...

  8. 解决Fragment中使用ViewPager时,ViewPager里的Fragment错位和空白问题

    这两天开始在改OSChina的开源android客户端,打算用Fragment来分离Main这个Activity里的功能.用Fragment嵌套ViewPager+Fragment的时候发现问题. 红 ...

  9. Android 开源框架ViewPageIndicator 和 ViewPager 仿网易新闻clientTab标签

    之前用JakeWharton的开源框架ActionBarSherlock和ViewPager实现了对网易新闻clientTab标签的功能,ActionBarSherlock是在3.0下面的机器支持Ac ...

随机推荐

  1. 【Android】YUV使用总结 —— Android常用的几种格式:NV21/NV12/YV12/YUV420P的区别

    工作问题接触到图像这一块,需要对手机摄像头采集的原始帧做Rotate或者scale,但无奈对此的了解少之又少,于是网上搜了一顿,完事后将最近所学总结一下,以方便之后的人别踩太多坑.       首先想 ...

  2. DPDK学习之开篇介绍

    1.前言 记得刚开始工作的时,老大将我安排到数据面组,当时第一次听说”数据面“这个概念,感觉挺新鲜的.误打误撞就开始搞了,刚开始接触的时候,由于不懂其中的原理,觉得很神奇,因为报文的转发是在应用层,通 ...

  3. 交换排序---冒泡排序算法(Javascript版)

    比较相邻的元素.如果第一个比第二个大,就交换他们两个.对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对.在这一点,最后的元素应该会是最大的数.针对所有的元素重复以上的步骤,除了最后一个.持续 ...

  4. Winform图片拖拽与缩放

    最近做项目的时候遇到上传施工平面布置图,查看,因为图片比较大,一般的显示器分辨率无法显示全,然后还需要放大看清楚图片里面的文字内容,所以需要用到图片的拖拽与缩放功能.这里整理下具体操作. 首先新建一个 ...

  5. inner join on, left join on, right join on的区别与介绍

    Table A aid   adate 1      a1 2      a2 3      a3 TableB bid bdate 1    b1 2   b2 4    b4 两个表a,b相连接, ...

  6. DataGridView修改HeaderText

    dataGridView_htList为一个 DataGridView(ht为HoverTree的缩写)方法一:dataGridView_htList.Columns["HtAddTime& ...

  7. iOS阶段学习第29天笔记(UITextField的介绍)

    iOS学习(UI)知识点整理 一.关于UITextField的介绍 1)概念: UITextField 是用于接收用户输入的一个控件 2)UITextField  初始化实例代码: //创建一个UIt ...

  8. C# 操作鼠标移动到指定的屏幕位置方法

    /// <summary> /// 引用user32.dll动态链接库(windows api), /// 使用库中定义 API:SetCursorPos /// </summary ...

  9. 怎样解决PowerDesigner15出现许可证过期问题?

    今天打开PowerDesigner软件,出现许可证过期问题,怎样解决 1)打开软件安装路径(通过搜索打开文件所在路径或通过软件图标的属性打开)

  10. 【软件使用】GitHub使用教程for Eclipse

    http://www.cnblogs.com/yc-755909659/p/3753626.html 1.下载egit插件 打开Eclipse,git需要eclipse授权,通过网页是无法下载egit ...