您的位置:首页 > 移动开发 > Android开发

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

2015-03-26 18:44 1176 查看
博客园
博问
闪存
首页
新随笔
联系
管理
订阅

随笔- 88  文章- 6  评论- 55 


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

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



如新浪微博下面的标签切换功能,我以前也写过一篇博文(http://www.cnblogs.com/tiantianbyconan/archive/2012/02/24/2366237.html),可以实现,用的是TabHost。但是android发展比较迅速,TabHost这玩意现在已经被弃用了,虽说用现在也能用,但是被弃用的东西还是少用为妙。
官方有个FragmentTabHost这么一个替代品,于是试了一下,发现每次切换tab,都会调用onCreateView()方法,控件被重新加载,也就是说你从tab1切换到别的tab后,再切换回来,tab1的状态并没有保存,重新加载了控件。
搞了半天,暂时没有好的解决办法(有朋友知道解决办法的话,希望联系我,赐教下哈)
于是,怒了,自己实现一个吧- -
 
先来看看整个demo的结构:



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



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:tiantian.china.2@gmail.com
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 }


如上述代码所示,TabAFm是一个Fragment,对应的布局文件是tab_a.xml,并实现了他的所有的生命周期回调函数并打印,便于调试
tab_a.xml布局中有个EditText
其他的Fragment大同小异,这里就不贴出代码了
 
现在来看MainActivity:



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 }


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的切换,如下:



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>


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

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


 
现在看下FragmentTabAdapter:



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:tiantian.china.2@gmail.com
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 }


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



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     }


// 获得绑定的FragmentActivity
MainActivity activity = ((MainActivity)getActivity());


通过getActivity()即可得到Fragment所在的FragmentActivity
 
最终效果图:



demo下载地址:http://pan.baidu.com/s/1wxsIX
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐