Android兩級導航選單欄的實現--FragmentTabHost+自定義二級導航選單欄
阿新 • • 發佈:2019-02-09
前兩篇博文分別採用 FragmentTabHost巢狀FragmentTabHost和FragmentTabHost+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,僅僅是提供思路,在實際專案開發中的情況複雜的多。
但願小生所做的事對別人有所幫助,就算莫大的榮幸了。