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的例子差不多:

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

TabAFm到TabEFm都是Fragment,并且每个Fragment对应一个布局文件。

TabAFm.java:

 

Android使用Fragment来实现ViewPager的功能(解决切换Fragment状态不保存)以及各个Fragment之间的通信
 1 package com.wangjie.fragmentviewpagertest;

 2 

 3 import android.app.Activity;

 4 import android.os.Bundle;

 5 import android.support.v4.app.Fragment;

 6 import android.view.LayoutInflater;

 7 import android.view.View;

 8 import android.view.ViewGroup;

 9 

10 /**

11  * Created with IntelliJ IDEA.

12  * Author: wangjie  email:[email protected]

13  * Date: 13-6-14

14  * Time: 下午2:39

15  */

16 public class TabAFm extends Fragment{

17     @Override

18     public void onAttach(Activity activity) {

19         super.onAttach(activity);

20         System.out.println("AAAAAAAAAA____onAttach");

21     }

22 

23     @Override

24     public void onCreate(Bundle savedInstanceState) {

25         super.onCreate(savedInstanceState);

26         System.out.println("AAAAAAAAAA____onCreate");

27     }

28 

29     @Override

30     public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

31         System.out.println("AAAAAAAAAA____onCreateView");

32         return inflater.inflate(R.layout.tab_a, container, false);

33     }

34 

35     @Override

36     public void onActivityCreated(Bundle savedInstanceState) {

37         super.onActivityCreated(savedInstanceState);

38         System.out.println("AAAAAAAAAA____onActivityCreated");

39     }

40 

41     @Override

42     public void onStart() {

43         super.onStart();

44         System.out.println("AAAAAAAAAA____onStart");

45     }

46 

47     @Override

48     public void onResume() {

49         super.onResume();

50         System.out.println("AAAAAAAAAA____onResume");

51     }

52 

53     @Override

54     public void onPause() {

55         super.onPause();

56         System.out.println("AAAAAAAAAA____onPause");

57     }

58 

59     @Override

60     public void onStop() {

61         super.onStop();

62         System.out.println("AAAAAAAAAA____onStop");

63     }

64 

65     @Override

66     public void onDestroyView() {

67         super.onDestroyView();

68         System.out.println("AAAAAAAAAA____onDestroyView");

69     }

70 

71     @Override

72     public void onDestroy() {

73         super.onDestroy();

74         System.out.println("AAAAAAAAAA____onDestroy");

75     }

76 

77     @Override

78     public void onDetach() {

79         super.onDetach();

80         System.out.println("AAAAAAAAAA____onDetach");

81     }

82 }
View Code

如上述代码所示,TabAFm是一个Fragment,对应的布局文件是tab_a.xml,并实现了他的所有的生命周期回调函数并打印,便于调试

tab_a.xml布局中有个EditText

其他的Fragment大同小异,这里就不贴出代码了

 

现在来看MainActivity:

Android使用Fragment来实现ViewPager的功能(解决切换Fragment状态不保存)以及各个Fragment之间的通信
 1 package com.wangjie.fragmentviewpagertest;

 2 

 3 import android.os.Bundle;

 4 import android.support.v4.app.Fragment;

 5 import android.support.v4.app.FragmentActivity;

 6 import android.support.v4.view.ViewPager;

 7 

 8 import java.util.ArrayList;

 9 import java.util.List;

10 

11 public class MainActivity extends FragmentActivity {

12     private ViewPager viewPager;

13     public List<Fragment> fragments = new ArrayList<Fragment>();

14     public String hello = "hello ";

15 

16     @Override

17     public void onCreate(Bundle savedInstanceState) {

18         super.onCreate(savedInstanceState);

19         setContentView(R.layout.main);

20 

21         fragments.add(new TabAFm());

22         fragments.add(new TabBFm());

23         fragments.add(new TabCFm());

24         fragments.add(new TabDFm());

25         fragments.add(new TabEFm());

26 

27         viewPager = (ViewPager) findViewById(R.id.viewPager);

28         FragmentViewPagerAdapter adapter = new FragmentViewPagerAdapter(this.getSupportFragmentManager(), viewPager,fragments);

29         adapter.setOnExtraPageChangeListener(new FragmentViewPagerAdapter.OnExtraPageChangeListener(){

30             @Override

31             public void onExtraPageSelected(int i) {

32                 System.out.println("Extra...i: " + i);

33             }

34         });

35 

36     }

37 

38 }
View Code

MainActivity上述代码所示

MainActivity是包含Fragment的Activity(也就是这里的5个Fragment)

他继承了FragmentActivity(因为我这里用的是android-support-v4.jar)

用一个List<Fragment>去维护5个Fragment,也就是5个page。

MainActivity的布局很简单,就一个ViewPager,main.xml如下:

Android使用Fragment来实现ViewPager的功能(解决切换Fragment状态不保存)以及各个Fragment之间的通信
 1 <?xml version="1.0" encoding="utf-8"?>

 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

 3               android:orientation="vertical"

 4               android:layout_width="fill_parent"

 5               android:layout_height="fill_parent"

 6         >

 7     <android.support.v4.view.ViewPager

 8         android:id="@+id/viewPager"

 9         android:layout_width="match_parent"

10         android:layout_height="match_parent"

11         />

12 

13 </LinearLayout>
View Code

 

现在回到MainActivity中,下面这个FragmentViewPagerAdapter类是关键,是我自己编写的用于绑定和处理fragments和ViewPager之间的逻辑关系

FragmentViewPagerAdapter adapter = new FragmentViewPagerAdapter(this.getSupportFragmentManager(), viewPager,fragments);

 

现在看下FragmentViewPagerAdapter:

Android使用Fragment来实现ViewPager的功能(解决切换Fragment状态不保存)以及各个Fragment之间的通信
  1 package com.wangjie.fragmentviewpagertest;

  2 

  3 import android.support.v4.app.Fragment;

  4 import android.support.v4.app.FragmentManager;

  5 import android.support.v4.app.FragmentTransaction;

  6 import android.support.v4.view.PagerAdapter;

  7 import android.support.v4.view.ViewPager;

  8 import android.view.View;

  9 import android.view.ViewGroup;

 10 

 11 import java.util.List;

 12 

 13 /**

 14  * 为ViewPager添加布局(Fragment),绑定和处理fragments和viewpager之间的逻辑关系

 15  *

 16  * Created with IntelliJ IDEA.

 17  * Author: wangjie  email:[email protected]

 18  * Date: 13-10-11

 19  * Time: 下午3:03

 20  */

 21 public class FragmentViewPagerAdapter extends PagerAdapter implements ViewPager.OnPageChangeListener{

 22     private List<Fragment> fragments; // 每个Fragment对应一个Page

 23     private FragmentManager fragmentManager;

 24     private ViewPager viewPager; // viewPager对象

 25     private int currentPageIndex = 0; // 当前page索引(切换之前)

 26 

 27     private OnExtraPageChangeListener onExtraPageChangeListener; // ViewPager切换页面时的额外功能添加接口

 28 

 29     public FragmentViewPagerAdapter(FragmentManager fragmentManager, ViewPager viewPager , List<Fragment> fragments) {

 30         this.fragments = fragments;

 31         this.fragmentManager = fragmentManager;

 32         this.viewPager = viewPager;

 33         this.viewPager.setAdapter(this);

 34         this.viewPager.setOnPageChangeListener(this);

 35     }

 36 

 37     @Override

 38     public int getCount() {

 39         return fragments.size();

 40     }

 41 

 42     @Override

 43     public boolean isViewFromObject(View view, Object o) {

 44         return view == o;

 45     }

 46 

 47     @Override

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

 49         container.removeView(fragments.get(position).getView()); // 移出viewpager两边之外的page布局

 50     }

 51 

 52     @Override

 53     public Object instantiateItem(ViewGroup container, int position) {

 54         Fragment fragment = fragments.get(position);

 55         if(!fragment.isAdded()){ // 如果fragment还没有added

 56             FragmentTransaction ft = fragmentManager.beginTransaction();

 57             ft.add(fragment, fragment.getClass().getSimpleName());

 58             ft.commit();

 59             /**

 60              * 在用FragmentTransaction.commit()方法提交FragmentTransaction对象后

 61              * 会在进程的主线程中,用异步的方式来执行。

 62              * 如果想要立即执行这个等待中的操作,就要调用这个方法(只能在主线程中调用)。

 63              * 要注意的是,所有的回调和相关的行为都会在这个调用中被执行完成,因此要仔细确认这个方法的调用位置。

 64              */

 65             fragmentManager.executePendingTransactions();

 66         }

 67 

 68         if(fragment.getView().getParent() == null){

 69             container.addView(fragment.getView()); // 为viewpager增加布局

 70         }

 71 

 72         return fragment.getView();

 73     }

 74 

 75     /**

 76      * 当前page索引(切换之前)

 77      * @return

 78      */

 79     public int getCurrentPageIndex() {

 80         return currentPageIndex;

 81     }

 82 

 83     public OnExtraPageChangeListener getOnExtraPageChangeListener() {

 84         return onExtraPageChangeListener;

 85     }

 86 

 87     /**

 88      * 设置页面切换额外功能监听器

 89      * @param onExtraPageChangeListener

 90      */

 91     public void setOnExtraPageChangeListener(OnExtraPageChangeListener onExtraPageChangeListener) {

 92         this.onExtraPageChangeListener = onExtraPageChangeListener;

 93     }

 94 

 95     @Override

 96     public void onPageScrolled(int i, float v, int i2) {

 97         if(null != onExtraPageChangeListener){ // 如果设置了额外功能接口

 98             onExtraPageChangeListener.onExtraPageScrolled(i, v, i2);

 99         }

100     }

101 

102     @Override

103     public void onPageSelected(int i) {

104         fragments.get(currentPageIndex).onPause(); // 调用切换前Fargment的onPause()

105 //        fragments.get(currentPageIndex).onStop(); // 调用切换前Fargment的onStop()

106         if(fragments.get(i).isAdded()){

107 //            fragments.get(i).onStart(); // 调用切换后Fargment的onStart()

108             fragments.get(i).onResume(); // 调用切换后Fargment的onResume()

109         }

110         currentPageIndex = i;

111 

112         if(null != onExtraPageChangeListener){ // 如果设置了额外功能接口

113             onExtraPageChangeListener.onExtraPageSelected(i);

114         }

115 

116     }

117 

118     @Override

119     public void onPageScrollStateChanged(int i) {

120         if(null != onExtraPageChangeListener){ // 如果设置了额外功能接口

121             onExtraPageChangeListener.onExtraPageScrollStateChanged(i);

122         }

123     }

124 

125 

126     /**

127      * page切换额外功能接口

128      */

129     static class OnExtraPageChangeListener{

130         public void onExtraPageScrolled(int i, float v, int i2){}

131         public void onExtraPageSelected(int i){}

132         public void onExtraPageScrollStateChanged(int i){}

133     }

134 

135 

136 }
View Code

这里解决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中:

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

 2     public void onActivityCreated(Bundle savedInstanceState) {

 3         super.onActivityCreated(savedInstanceState);

 4         System.out.println("BBBBBBBBBBB____onActivityCreated");

 5         this.getView().findViewById(R.id.clickme).setOnClickListener(new View.OnClickListener() {

 6             @Override

 7             public void onClick(View view) {

 8                 // 获得绑定的FragmentActivity

 9                 MainActivity activity = ((MainActivity)getActivity());

10                 // 获得TabAFm的控件

11                 EditText editText = (EditText) activity.fragments.get(0).getView().findViewById(R.id.edit);

12 

13                 Toast.makeText(activity, activity.hello + editText.getText(), Toast.LENGTH_SHORT).show();

14             }

15         });

16     }
View Code

 

最终效果图:

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

 

demo下载:http://pan.baidu.com/s/1stGQ7

你可能感兴趣的:(viewpager)