Android两级导航菜单栏的实现--FragmentTabHost+自定义二级导航菜单栏

  前两篇博文分别采用 FragmentTabHost嵌套FragmentTabHost和FragmentTabHost+PagerSlidingTabStrip 与ViewPager的方式实现了子Tab导航菜单栏的效果,虽是好用,但有时候却不灵活。

        本篇中将要实现自定义Tab导航菜单栏效果。

        如果你对FragmentTabHost和Fragment还不熟悉,一定要先看前面的博文。

仍然先看看效果图

 

重写fragment_message1.xml

 

[html] view plain copy
 
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:layout_width="match_parent"  
  4.     android:layout_height="match_parent"  
  5.     android:background="#F5F7FA"  
  6.     android:orientation="vertical" >  
  7.   
  8.     <include layout="@layout/top_sub_tab" />  
  9.   
  10.     <FrameLayout  
  11.         android:id="@+id/id_content"  
  12.         android:layout_width="fill_parent"  
  13.         android:layout_height="0dp"  
  14.         android:layout_weight="1" >  
  15.     </FrameLayout>  
  16.   
  17. </LinearLayout>  

 

 

顶部的Tab导航为自定义top_sub_tab.xml

 

        当然,你可以随心所欲的打造出符合业务需要的样式

 

[html] view plain copy
 
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:layout_width="match_parent"  
  4.     android:layout_height="40dp"  
  5.     android:background="#eee"  
  6.     android:orientation="vertical" >  
  7.   
  8.     <LinearLayout  
  9.         android:layout_width="fill_parent"  
  10.         android:layout_height="37dp"  
  11.         android:orientation="horizontal" >  
  12.   
  13.         <LinearLayout  
  14.             android:id="@+id/lin_sub1"  
  15.             android:layout_width="3dp"  
  16.             android:orientation="horizontal"  
  17.             android:layout_height="fill_parent"  
  18.             android:layout_weight="1"  
  19.             android:gravity="center" >  
  20.   
  21.             <TextView  
  22.                 android:layout_width="wrap_content"  
  23.                 android:layout_height="wrap_content"  
  24.                 android:text="新闻"  
  25.                 android:textColor="#008000" />  
  26.         </LinearLayout>  
  27.   
  28.         <LinearLayout  
  29.              android:id="@+id/lin_sub2"  
  30.             android:layout_width="3dp"  
  31.             android:layout_height="fill_parent"  
  32.             android:layout_weight="1"  
  33.             android:gravity="center" >  
  34.   
  35.             <TextView  
  36.                  
  37.                 android:layout_width="wrap_content"  
  38.                 android:layout_height="wrap_content"  
  39.                 android:textColor="#000000"  
  40.                 android:text="财经" />  
  41.         </LinearLayout>  
  42.   
  43.         <LinearLayout  
  44.              android:id="@+id/lin_sub3"  
  45.             android:layout_width="3dp"  
  46.             android:layout_height="fill_parent"  
  47.             android:layout_weight="1"  
  48.             android:gravity="center" >  
  49.   
  50.             <TextView  
  51.                 android:layout_width="wrap_content"  
  52.                 android:layout_height="wrap_content"  
  53.                 android:textColor="#000000"  
  54.                 android:text="旅游" />  
  55.         </LinearLayout>  
  56.     </LinearLayout>  
  57.   
  58.     <ImageView  
  59.         android:id="@+id/imv_tabline"  
  60.         android:layout_width="100dp"  
  61.         android:layout_height="3dp"  
  62.         android:background="#FF8D42" />  
  63.   
  64. </LinearLayout>  

 

 

重写 FragmentMessage

 

 

[java] view plain copy
 
  1. public class FragmentMessage extends Fragment implements OnClickListener {  
  2.       
  3.     private static String  TAG = FragmentMessage.class.getName();  
  4.   
  5.     private LinearLayout lin_sub1, lin_sub2, lin_sub3;  
  6.       
  7.     private Fragment subFragment1;  
  8.     private Fragment subFragment2;  
  9.     private Fragment subFragment3;  
  10.       
  11.     private ImageView mTabline;  
  12.     private int mScreen1_3;  
  13.       
  14.   
  15.     @Override  
  16.     public void onCreate(Bundle savedInstanceState) {  
  17.   
  18.         super.onCreate(savedInstanceState);  
  19.   
  20.         Bundle bundle = getArguments();  
  21.         if (null != bundle) {  
  22.             //  
  23.         }  
  24.     }  
  25.   
  26.     @Override  
  27.     public View onCreateView(LayoutInflater inflater, ViewGroup container,  
  28.             Bundle savedInstanceState) {  
  29.         T.showShort(getActivity(), "FragmentMessage==onCreateView");  
  30.         View view = inflater.inflate(R.layout.fragment_message1, null);  
  31.   
  32.         initView(view);  
  33.         setLinstener();  
  34.         initData();  
  35.         return view;  
  36.     }  
  37.   
  38.     private void initView(View view) {  
  39.   
  40.         lin_sub1 = (LinearLayout) view.findViewById(R.id.lin_sub1);  
  41.         lin_sub2 = (LinearLayout) view.findViewById(R.id.lin_sub2);  
  42.         lin_sub3 = (LinearLayout) view.findViewById(R.id.lin_sub3);  
  43.         mTabline = (ImageView) view.findViewById(R.id.imv_tabline);  
  44.   
  45.     }  
  46.   
  47.     protected void initData() {  
  48.         // Display display = getWindow().getWindowManager().getDefaultDisplay();  
  49.         Display display = getActivity().getWindowManager().getDefaultDisplay();  
  50.         DisplayMetrics outMetrics = new DisplayMetrics();  
  51.         display.getMetrics(outMetrics);  
  52.         mScreen1_3 = outMetrics.widthPixels / 3;  
  53.         LayoutParams lp = (LayoutParams) mTabline.getLayoutParams();  
  54.         lp.width = mScreen1_3;  
  55.         mTabline.setLayoutParams(lp);  
  56.           
  57.         //初次显示设置  
  58.         setSubFragment(0);  
  59.         setmTabline(0);  
  60.   
  61.     }  
  62.   
  63.     protected void setLinstener() {  
  64.         lin_sub1.setOnClickListener(this);  
  65.         lin_sub2.setOnClickListener(this);  
  66.         lin_sub3.setOnClickListener(this);  
  67.   
  68.     }  
  69.   
  70.     @Override  
  71.     public void onClick(View v) {  
  72.         switch (v.getId()) {  
  73.         case R.id.lin_sub1:  
  74.             setSubFragment(0);  
  75.             setmTabline(0);  
  76.             break;  
  77.         case R.id.lin_sub2:  
  78.             setSubFragment(1);  
  79.             setmTabline(1);  
  80.             break;  
  81.         case R.id.lin_sub3:  
  82.             setSubFragment(2);  
  83.             setmTabline(2);  
  84.             break;  
  85.         default:  
  86.             break;  
  87.         }  
  88.   
  89.     }  
  90.   
  91.     public void setmTabline(int i) {  
  92.   
  93.         LinearLayout.LayoutParams lp = (android.widget.LinearLayout.LayoutParams) mTabline  
  94.                 .getLayoutParams();  
  95.         lp.leftMargin = i * mScreen1_3;  
  96.         mTabline.setLayoutParams(lp);  
  97.   
  98.     }  
  99.       
  100.     public void setSubFragment(int i){  
  101.           
  102.         FragmentTransaction transaction =getFragmentManager().beginTransaction();  
  103.           
  104.         if(0 == i ){      
  105.             subFragment1 = (subFragment1 == null ? new  SubFragment1():subFragment1);  
  106.                 transaction.replace(R.id.id_content,subFragment1);    
  107.         //  transaction.addToBackStack(null);  
  108.             transaction.commit();  
  109.               
  110.         }else if(1 == i ){  
  111.             subFragment2 = (subFragment2 == null ? new  SubFragment2():subFragment2);  
  112.             transaction.replace(R.id.id_content,subFragment2);    
  113.         //  transaction.addToBackStack(null);  
  114.             transaction.commit();  
  115.         }else if(2 == i ){  
  116.             subFragment3 = (subFragment3 == null ? new  SubFragment3():subFragment3);  
  117.             transaction.replace(R.id.id_content,subFragment3);    
  118.         //  transaction.addToBackStack(null);  
  119.             transaction.commit();  
  120.         }         
  121.           
  122.     }  
  123.       
  124.   
  125. }  

 

再添加 SubFragment1(这里只给出一个,其它类似)

 

 

[java] view plain copy
 
  1. public class SubFragment1 extends Fragment {  
  2.   
  3.     @Override  
  4.     public View onCreateView(LayoutInflater inflater, ViewGroup container,  
  5.             Bundle savedInstanceState) {  
  6.         T.showShort(getActivity(), "SubFragment1==onCreateView");  
  7.         TextView tv = new TextView(getActivity());  
  8.         tv.setTextSize(25);  
  9.         tv.setBackgroundColor(Color.parseColor("#FFA07A"));  
  10.         tv.setText("新闻");  
  11.         tv.setGravity(Gravity.CENTER);  
  12.         return tv;  
  13.     }  
  14. }  


        好了,代码就这么简单……你会发现每次切换二级Tab导航菜单栏的时候,子Fragment会重新绘制,只需再稍微改造一下就OK了

 

 

[java] view plain copy
 
  1. /* 
  2.      * 显示subFragment,subFragment不会重复onCreateView 
  3.      */  
  4.     public void showSubFragment(int i) {  
  5.   
  6.         FragmentTransaction transaction = getFragmentManager()  
  7.                 .beginTransaction();  
  8.         hideSubFragment(transaction);  
  9.         if (0 == i) {  
  10.             subFragment1 = (subFragment1 == null ? new SubFragment1()  
  11.                     : subFragment1);  
  12.             if(!subFragment1.isAdded()){  
  13.                 transaction.add(R.id.id_content, subFragment1);  
  14.             }             
  15.             // transaction.addToBackStack(null);  
  16.             transaction.show(subFragment1);  
  17.             transaction.commit();  
  18.   
  19.         } else if (1 == i) {  
  20.             subFragment2 = (subFragment2 == null ? new SubFragment2()  
  21.                     : subFragment2);  
  22.             if(!subFragment2.isAdded()){  
  23.                 transaction.add(R.id.id_content, subFragment2);   
  24.             }  
  25.             // transaction.addToBackStack(null);  
  26.             transaction.show(subFragment2);  
  27.             transaction.commit();  
  28.         } else if (2 == i) {  
  29.             subFragment3 = (subFragment3 == null ? new SubFragment3()  
  30.                     : subFragment3);  
  31.             if(!subFragment3.isAdded()){  
  32.                 transaction.add(R.id.id_content, subFragment3);   
  33.             }  
  34.             // transaction.addToBackStack(null);  
  35.             transaction.show(subFragment3);  
  36.             transaction.commit();  
  37.         }  
  38.   
  39.     }  
  40.   
  41.     public void hideSubFragment(FragmentTransaction transaction) {  
  42.   
  43.         if (subFragment1 != null) {  
  44.             transaction.hide(subFragment1);  
  45.         }  
  46.         if (subFragment2 != null) {  
  47.             transaction.hide(subFragment2);  
  48.         }  
  49.         if (subFragment3 != null) {  
  50.             transaction.hide(subFragment3);  
  51.         }  
  52.   
  53.     }  

 

 

几点注意的地方:

        1  在transaction.add()方法时候,先判断subFragment1.isAdded(),避免该异常:java.lang.IllegalStateException: Fragment already added: 
        2  FragmentTransaction事务 只能执行一次commit()操作,所以定义成局部变量。
        3  transaction.replace()时有一个移除操作和一个添加操作,即先remove()再add(),remove()的时候Fragment实例已经被销毁,所以在方式一种每次切换子Tab导航菜单栏,subFragment都会执行OncreateView();
        4  hide()和show()方法,看字面意义就理解了。hide()只是隐藏,不会销毁,而show()就是把隐藏的显示出来。

 

        关于Android Tab导航菜单栏--FragmentTabHost+Fragment的博客就到这里了。小生不权威,肯定有很多疏漏和出错的地方,想好好玩Android,看谷歌官方文档和Android源码才是王道。
        小生这里只是写的一些超级基础的Demo,仅仅是提供思路,在实际项目开发中的情况复杂的多。
        但愿小生所做的事对别人有所帮助,就算莫大的荣幸了。

Demo下载地址(子Fragment会重复onCreateView):http://download.csdn.net/detail/yalinfendou/8543999

Demo下载地址(子Fragment不会重复onCreateView):http://download.csdn.net/detail/yalinfendou/8544017

posted @ 2016-11-30 21:14  天涯海角路  阅读(562)  评论(0)    收藏  举报