1. 程式人生 > >Android兩級導航選單欄的實現--FragmentTabHost+自定義二級導航選單欄

Android兩級導航選單欄的實現--FragmentTabHost+自定義二級導航選單欄

        前兩篇博文分別採用 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;
	

	@Override
	public void onCreate(Bundle savedInstanceState) {

		super.onCreate(savedInstanceState);

		Bundle bundle = getArguments();
		if (null != bundle) {
			//
		}
	}

	@Override
	public 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);

	}

	@Override
	public 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){
		
		FragmentTransaction	transaction =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 {

	@Override
	public 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,僅僅是提供思路,在實際專案開發中的情況複雜的多。
但願小生所做的事對別人有所幫助,就算莫大的榮幸了。