zoukankan      html  css  js  c++  java
  • 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的结构:

    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

     

    最终效果图:

  • 相关阅读:
    python爬虫基础(requests、BeautifulSoup)
    python中字典按键、值进行排序
    进程和线程的区别
    MySQL中的索引
    python中浅拷贝和深拷贝的区别
    谈谈final、finally、finalize的区别
    python中布尔值是false
    生成器的阐释
    文件处理
    内置函数
  • 原文地址:https://www.cnblogs.com/Free-Thinker/p/3662785.html
Copyright © 2011-2022 走看看