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

以下内容为原创,转载请注明:http://www.cnblogs.com/tiantianbyconan/p/3360938.html

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

如新浪微博下面的标签切换功能,我以前也写过一篇博文(http://www.cnblogs.com/tiantianbyconan/archive/2012/02/24/2366237.html),可以实现,用的是TabHost。但是android发展比较迅速,TabHost这玩意现在已经被弃用了,虽说用现在也能用,但是被弃用的东西还是少用为妙。

官方有个FragmentTabHost这么一个替代品,于是试了一下,发现每次切换tab,都会调用onCreateView()方法,控件被重新加载,也就是说你从tab1切换到别的tab后,再切换回来,tab1的状态并没有保存,重新加载了控件。

搞了半天,暂时没有好的解决办法(有朋友知道解决办法的话,希望联系我,赐教下哈)

于是,怒了,自己实现一个吧- -

 

先来看看整个demo的结构:

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

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

TabAFm.java:

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

 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来实现TabHost的功能(解决切换Fragment状态不保存)以及各个Fragment之间的通信
 1 package com.wangjie.fragmenttabhost;

 2 

 3 import android.os.Bundle;

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

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

 6 import android.widget.RadioGroup;

 7 

 8 import java.util.ArrayList;

 9 import java.util.List;

10 

11 public class MainActivity extends FragmentActivity {

12     /**

13      * Called when the activity is first created.

14      */

15     private RadioGroup rgs;

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

17 

18     public String hello = "hello ";

19 

20     @Override

21     public void onCreate(Bundle savedInstanceState) {

22         super.onCreate(savedInstanceState);

23         setContentView(R.layout.main);

24 

25         fragments.add(new TabAFm());

26         fragments.add(new TabBFm());

27         fragments.add(new TabCFm());

28         fragments.add(new TabDFm());

29         fragments.add(new TabEFm());

30 

31 

32         rgs = (RadioGroup) findViewById(R.id.tabs_rg);

33 

34         FragmentTabAdapter tabAdapter = new FragmentTabAdapter(this, fragments, R.id.tab_content, rgs);

35         tabAdapter.setOnRgsExtraCheckedChangedListener(new FragmentTabAdapter.OnRgsExtraCheckedChangedListener(){

36             @Override

37             public void OnRgsExtraCheckedChanged(RadioGroup radioGroup, int checkedId, int index) {

38                 System.out.println("Extra---- " + index + " checked!!! ");

39             }

40         });

41 

42     }

43 

44 }
View Code

MainActivity上述代码所示

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

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

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

main布局中有一个id为tab_content的FrameLayout,用来存放要显示的Fragment。底部有一个RadioGroup,用于tab的切换,如下:

Android使用Fragment来实现TabHost的功能(解决切换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               android:background="@android:color/white"

  7         >

  8     <LinearLayout

  9             android:layout_width="fill_parent"

 10             android:layout_height="fill_parent"

 11             android:orientation="vertical"

 12         >

 13 

 14     <FrameLayout

 15             android:id="@+id/tab_content"

 16             android:layout_width="fill_parent"

 17             android:layout_height="0dp"

 18             android:layout_weight="1.0"

 19             android:background="#77557799"

 20             />

 21 

 22     <RadioGroup

 23             android:id="@+id/tabs_rg"

 24             android:layout_width="fill_parent"

 25             android:layout_height="wrap_content"

 26             android:orientation="horizontal"

 27             android:gravity="center"

 28             android:paddingTop="7dp"

 29             android:paddingBottom="7dp"

 30             >

 31         <RadioButton

 32                 android:id="@+id/tab_rb_a"

 33                 android:layout_width="0dp"

 34                 android:layout_height="wrap_content"

 35                 android:drawableTop="@drawable/tablatestalert"

 36                 android:button="@null"

 37                 android:text="Tab1"

 38                 android:textColor="#000000"

 39                 android:textSize="13sp"

 40                 android:layout_weight="1.0"

 41                 android:gravity="center"

 42                 android:singleLine="true"

 43                 android:checked="true"

 44                 android:background="@drawable/selector_tab"

 45                 />

 46         <RadioButton

 47                 android:id="@+id/tab_rb_b"

 48                 android:layout_width="0dp"

 49                 android:layout_height="wrap_content"

 50                 android:drawableTop="@drawable/tabsearch"

 51                 android:button="@null"

 52                 android:text="Tab2"

 53                 android:textColor="#000000"

 54                 android:textSize="13sp"

 55                 android:layout_weight="1.0"

 56                 android:gravity="center"

 57                 android:singleLine="true"

 58                 android:background="@drawable/selector_tab"

 59                 />

 60         <RadioButton

 61                 android:id="@+id/tab_rb_c"

 62                 android:layout_width="0dp"

 63                 android:layout_height="wrap_content"

 64                 android:drawableTop="@drawable/tabrecommd"

 65                 android:button="@null"

 66                 android:text="Tab3"

 67                 android:textColor="#000000"

 68                 android:textSize="13sp"

 69                 android:layout_weight="1.0"

 70                 android:gravity="center"

 71                 android:singleLine="true"

 72                 android:background="@drawable/selector_tab"

 73                 />

 74         <RadioButton

 75                 android:id="@+id/tab_rb_d"

 76                 android:layout_width="0dp"

 77                 android:layout_height="wrap_content"

 78                 android:drawableTop="@drawable/tabconfigicon"

 79                 android:button="@null"

 80                 android:text="Tab4"

 81                 android:textColor="#000000"

 82                 android:textSize="13sp"

 83                 android:layout_weight="1.0"

 84                 android:gravity="center"

 85                 android:singleLine="true"

 86                 android:background="@drawable/selector_tab"

 87                 />

 88         <RadioButton

 89                 android:id="@+id/tab_rb_e"

 90                 android:layout_width="0dp"

 91                 android:layout_height="wrap_content"

 92                 android:drawableTop="@drawable/tababoutus"

 93                 android:button="@null"

 94                 android:text="Tab5"

 95                 android:textColor="#000000"

 96                 android:textSize="13sp"

 97                 android:layout_weight="1.0"

 98                 android:gravity="center"

 99                 android:singleLine="true"

100                 android:background="@drawable/selector_tab"

101                 />

102 

103     </RadioGroup>

104     </LinearLayout>

105 </LinearLayout>
View Code

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

FragmentTabAdapter tabAdapter = new FragmentTabAdapter(this, fragments, R.id.tab_content, rgs);

 

现在看下FragmentTabAdapter:

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

  2 

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

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

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

  6 import android.widget.RadioGroup;

  7 

  8 import java.util.List;

  9 

 10 /**

 11  * Created with IntelliJ IDEA.

 12  * Author: wangjie  email:[email protected]

 13  * Date: 13-10-10

 14  * Time: 上午9:25

 15  */

 16 public class FragmentTabAdapter implements RadioGroup.OnCheckedChangeListener{

 17     private List<Fragment> fragments; // 一个tab页面对应一个Fragment

 18     private RadioGroup rgs; // 用于切换tab

 19     private FragmentActivity fragmentActivity; // Fragment所属的Activity

 20     private int fragmentContentId; // Activity中所要被替换的区域的id

 21 

 22     private int currentTab; // 当前Tab页面索引

 23 

 24     private OnRgsExtraCheckedChangedListener onRgsExtraCheckedChangedListener; // 用于让调用者在切换tab时候增加新的功能

 25 

 26     public FragmentTabAdapter(FragmentActivity fragmentActivity, List<Fragment> fragments, int fragmentContentId, RadioGroup rgs) {

 27         this.fragments = fragments;

 28         this.rgs = rgs;

 29         this.fragmentActivity = fragmentActivity;

 30         this.fragmentContentId = fragmentContentId;

 31 

 32         // 默认显示第一页

 33         FragmentTransaction ft = fragmentActivity.getSupportFragmentManager().beginTransaction();

 34         ft.add(fragmentContentId, fragments.get(0));

 35         ft.commit();

 36 

 37         rgs.setOnCheckedChangeListener(this);

 38 

 39 

 40     }

 41 

 42     @Override

 43     public void onCheckedChanged(RadioGroup radioGroup, int checkedId) {

 44         for(int i = 0; i < rgs.getChildCount(); i++){

 45             if(rgs.getChildAt(i).getId() == checkedId){

 46                 Fragment fragment = fragments.get(i);

 47                 FragmentTransaction ft = obtainFragmentTransaction(i);

 48 

 49                 getCurrentFragment().onPause(); // 暂停当前tab

 50 //                getCurrentFragment().onStop(); // 暂停当前tab

 51 

 52                 if(fragment.isAdded()){

 53 //                    fragment.onStart(); // 启动目标tab的onStart()

 54                     fragment.onResume(); // 启动目标tab的onResume()

 55                 }else{

 56                     ft.add(fragmentContentId, fragment);

 57                 }

 58                 showTab(i); // 显示目标tab

 59                 ft.commit();

 60 

 61                 // 如果设置了切换tab额外功能功能接口

 62                 if(null != onRgsExtraCheckedChangedListener){

 63                     onRgsExtraCheckedChangedListener.OnRgsExtraCheckedChanged(radioGroup, checkedId, i);

 64                 }

 65 

 66             }

 67         }

 68 

 69     }

 70 

 71     /**

 72      * 切换tab

 73      * @param idx

 74      */

 75     private void showTab(int idx){

 76         for(int i = 0; i < fragments.size(); i++){

 77             Fragment fragment = fragments.get(i);

 78             FragmentTransaction ft = obtainFragmentTransaction(idx);

 79 

 80             if(idx == i){

 81                 ft.show(fragment);

 82             }else{

 83                 ft.hide(fragment);

 84             }

 85             ft.commit();

 86         }

 87         currentTab = idx; // 更新目标tab为当前tab

 88     }

 89 

 90     /**

 91      * 获取一个带动画的FragmentTransaction

 92      * @param index

 93      * @return

 94      */

 95     private FragmentTransaction obtainFragmentTransaction(int index){

 96         FragmentTransaction ft = fragmentActivity.getSupportFragmentManager().beginTransaction();

 97         // 设置切换动画

 98         if(index > currentTab){

 99             ft.setCustomAnimations(R.anim.slide_left_in, R.anim.slide_left_out);

100         }else{

101             ft.setCustomAnimations(R.anim.slide_right_in, R.anim.slide_right_out);

102         }

103         return ft;

104     }

105 

106     public int getCurrentTab() {

107         return currentTab;

108     }

109 

110     public Fragment getCurrentFragment(){

111         return fragments.get(currentTab);

112     }

113 

114     public OnRgsExtraCheckedChangedListener getOnRgsExtraCheckedChangedListener() {

115         return onRgsExtraCheckedChangedListener;

116     }

117 

118     public void setOnRgsExtraCheckedChangedListener(OnRgsExtraCheckedChangedListener onRgsExtraCheckedChangedListener) {

119         this.onRgsExtraCheckedChangedListener = onRgsExtraCheckedChangedListener;

120     }

121 

122     /**

123      *  切换tab额外功能功能接口

124      */

125     static class OnRgsExtraCheckedChangedListener{

126         public void OnRgsExtraCheckedChanged(RadioGroup radioGroup, int checkedId, int index){

127 

128         }

129     }

130 

131 }
View Code

这里解决Fragment切换重新加载布局的办法,用的是把几个Fragment全部Add,然后根据要显示的哪个Fragment设置show或者hide

效果输出:

10-10 11:55:41.168: INFO/System.out(18368): AAAAAAAAAA____onAttach      // 第一次进入,显示TabA
10-10 11:55:41.168: INFO/System.out(18368): AAAAAAAAAA____onCreate
10-10 11:55:41.168: INFO/System.out(18368): AAAAAAAAAA____onCreateView
10-10 11:55:41.175: INFO/System.out(18368): AAAAAAAAAA____onActivityCreated
10-10 11:55:41.179: INFO/System.out(18368): AAAAAAAAAA____onStart
10-10 11:55:41.179: INFO/System.out(18368): AAAAAAAAAA____onResume
10-10 11:55:44.980: INFO/System.out(18368): AAAAAAAAAA____onPause      // 从TabA切换到TabB(TabA调用onPause)
10-10 11:55:44.980: INFO/System.out(18368): Extra---- 1 checked!!!
10-10 11:55:44.996: INFO/System.out(18368): BBBBBBBBBBB____onAttach
10-10 11:55:44.996: INFO/System.out(18368): BBBBBBBBBBB____onCreate
10-10 11:55:44.996: INFO/System.out(18368): BBBBBBBBBBB____onCreateView
10-10 11:55:45.004: INFO/System.out(18368): BBBBBBBBBBB____onActivityCreated
10-10 11:55:45.004: INFO/System.out(18368): BBBBBBBBBBB____onStart
10-10 11:55:45.004: INFO/System.out(18368): BBBBBBBBBBB____onResume
10-10 11:55:52.062: INFO/System.out(18368): BBBBBBBBBBB____onPause      // 从TabB切换到TabC(TabB调用onPause)
10-10 11:55:52.062: INFO/System.out(18368): Extra---- 2 checked!!!
10-10 11:55:52.082: INFO/System.out(18368): CCCCCCCCCC____onAttach
10-10 11:55:52.082: INFO/System.out(18368): CCCCCCCCCC____onCreate
10-10 11:55:52.086: INFO/System.out(18368): CCCCCCCCCC____onCreateView
10-10 11:55:52.090: INFO/System.out(18368): CCCCCCCCCC____onActivityCreated
10-10 11:55:52.090: INFO/System.out(18368): CCCCCCCCCC____onStart
10-10 11:55:52.090: INFO/System.out(18368): CCCCCCCCCC____onResume
10-10 11:56:06.535: INFO/System.out(18368): CCCCCCCCCC____onPause      // 从TabC切换到TabB(TabC调用onPause)
10-10 11:56:06.535: INFO/System.out(18368): BBBBBBBBBBB____onResume    // 从TabC切换到TabB(TabB调用onResume)
10-10 11:56:06.535: INFO/System.out(18368): Extra---- 1 checked!!!

 

好了,到此为止,我们已经用Fragment实现了类似TabHost的功能了,下面来看下各个Fragment之间的通信

现在的情况是TabAFm中有个EditText,TabBFm中有个Button,MainActivity中有个变量“hello”

要做的是,切换到TabA,输入“I'm TabA”,切换到B,点击Button后,Toast显示“hello I'm TabA”

MainActivity中没什么好说的,就一个hello变量:

public String hello = "hello ";

TabAFm在布局文件tab_a.xml中加个EditText,设置个id就可以了

TabBFm中:

Android使用Fragment来实现TabHost的功能(解决切换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
// 获得绑定的FragmentActivity

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

通过getActivity()即可得到Fragment所在的FragmentActivity

 

最终效果图:

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

demo下载地址:http://pan.baidu.com/s/1wxsIX

你可能感兴趣的:(Fragment)