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

来源:互联网 发布:西安高新区软件新城 编辑:程序博客网 时间:2024/05/21 22:24

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

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

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

仍然先看看效果图

 

重写fragment_message1.xml

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:background="#F5F7FA"    android:orientation="vertical" >    <include layout="@layout/top_sub_tab" />    <FrameLayout        android:id="@+id/id_content"        android:layout_width="fill_parent"        android:layout_height="0dp"        android:layout_weight="1" >    </FrameLayout></LinearLayout>

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

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

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="40dp"    android:background="#eee"    android:orientation="vertical" >    <LinearLayout        android:layout_width="fill_parent"        android:layout_height="37dp"        android:orientation="horizontal" >        <LinearLayout            android:id="@+id/lin_sub1"            android:layout_width="3dp"            android:orientation="horizontal"            android:layout_height="fill_parent"            android:layout_weight="1"            android:gravity="center" >            <TextView                android:layout_width="wrap_content"                android:layout_height="wrap_content"                android:text="新闻"                android:textColor="#008000" />        </LinearLayout>        <LinearLayout             android:id="@+id/lin_sub2"            android:layout_width="3dp"            android:layout_height="fill_parent"            android:layout_weight="1"            android:gravity="center" >            <TextView                               android:layout_width="wrap_content"                android:layout_height="wrap_content"                android:textColor="#000000"                android:text="财经" />        </LinearLayout>        <LinearLayout             android:id="@+id/lin_sub3"            android:layout_width="3dp"            android:layout_height="fill_parent"            android:layout_weight="1"            android:gravity="center" >            <TextView                android:layout_width="wrap_content"                android:layout_height="wrap_content"                android:textColor="#000000"                android:text="旅游" />        </LinearLayout>    </LinearLayout>    <ImageView        android:id="@+id/imv_tabline"        android:layout_width="100dp"        android:layout_height="3dp"        android:background="#FF8D42" /></LinearLayout>

重写 FragmentMessage

public class FragmentMessage extends Fragment implements OnClickListener {private static String  TAG = FragmentMessage.class.getName();private LinearLayout lin_sub1, lin_sub2, lin_sub3;private Fragment subFragment1;private Fragment subFragment2;private Fragment subFragment3;private ImageView mTabline;private int mScreen1_3;@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);Bundle bundle = getArguments();if (null != bundle) {//}}@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {T.showShort(getActivity(), "FragmentMessage==onCreateView");View view = inflater.inflate(R.layout.fragment_message1, null);initView(view);setLinstener();initData();return view;}private void initView(View view) {lin_sub1 = (LinearLayout) view.findViewById(R.id.lin_sub1);lin_sub2 = (LinearLayout) view.findViewById(R.id.lin_sub2);lin_sub3 = (LinearLayout) view.findViewById(R.id.lin_sub3);mTabline = (ImageView) view.findViewById(R.id.imv_tabline);}protected void initData() {// Display display = getWindow().getWindowManager().getDefaultDisplay();Display display = getActivity().getWindowManager().getDefaultDisplay();DisplayMetrics outMetrics = new DisplayMetrics();display.getMetrics(outMetrics);mScreen1_3 = outMetrics.widthPixels / 3;LayoutParams lp = (LayoutParams) mTabline.getLayoutParams();lp.width = mScreen1_3;mTabline.setLayoutParams(lp);//初次显示设置setSubFragment(0);setmTabline(0);}protected void setLinstener() {lin_sub1.setOnClickListener(this);lin_sub2.setOnClickListener(this);lin_sub3.setOnClickListener(this);}@Overridepublic void onClick(View v) {switch (v.getId()) {case R.id.lin_sub1:setSubFragment(0);setmTabline(0);break;case R.id.lin_sub2:setSubFragment(1);setmTabline(1);break;case R.id.lin_sub3:setSubFragment(2);setmTabline(2);break;default:break;}}public void setmTabline(int i) {LinearLayout.LayoutParams lp = (android.widget.LinearLayout.LayoutParams) mTabline.getLayoutParams();lp.leftMargin = i * mScreen1_3;mTabline.setLayoutParams(lp);}public void setSubFragment(int i){FragmentTransactiontransaction =getFragmentManager().beginTransaction();if(0 == i ){subFragment1 = (subFragment1 == null ? new  SubFragment1():subFragment1);transaction.replace(R.id.id_content,subFragment1);//transaction.addToBackStack(null);transaction.commit();}else if(1 == i ){subFragment2 = (subFragment2 == null ? new  SubFragment2():subFragment2);transaction.replace(R.id.id_content,subFragment2);//transaction.addToBackStack(null);transaction.commit();}else if(2 == i ){subFragment3 = (subFragment3 == null ? new  SubFragment3():subFragment3);transaction.replace(R.id.id_content,subFragment3);//transaction.addToBackStack(null);transaction.commit();}}}

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

public class SubFragment1 extends Fragment {@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {T.showShort(getActivity(), "SubFragment1==onCreateView");TextView tv = new TextView(getActivity());tv.setTextSize(25);tv.setBackgroundColor(Color.parseColor("#FFA07A"));tv.setText("新闻");tv.setGravity(Gravity.CENTER);return tv;}}

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

/* * 显示subFragment,subFragment不会重复onCreateView */public void showSubFragment(int i) {FragmentTransaction transaction = getFragmentManager().beginTransaction();hideSubFragment(transaction);if (0 == i) {subFragment1 = (subFragment1 == null ? new SubFragment1(): subFragment1);if(!subFragment1.isAdded()){transaction.add(R.id.id_content, subFragment1);}// transaction.addToBackStack(null);transaction.show(subFragment1);transaction.commit();} else if (1 == i) {subFragment2 = (subFragment2 == null ? new SubFragment2(): subFragment2);if(!subFragment2.isAdded()){transaction.add(R.id.id_content, subFragment2);}// transaction.addToBackStack(null);transaction.show(subFragment2);transaction.commit();} else if (2 == i) {subFragment3 = (subFragment3 == null ? new SubFragment3(): subFragment3);if(!subFragment3.isAdded()){transaction.add(R.id.id_content, subFragment3);}// transaction.addToBackStack(null);transaction.show(subFragment3);transaction.commit();}}public void hideSubFragment(FragmentTransaction transaction) {if (subFragment1 != null) {transaction.hide(subFragment1);}if (subFragment2 != null) {transaction.hide(subFragment2);}if (subFragment3 != null) {transaction.hide(subFragment3);}}

几点注意的地方:

        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

3 0