android使用Fragment實現底部選單使用show()和hide()來切換以保持Fragment狀態
在android開發的佈局中,國內大量的使用底部選單,這個本來不符合android的規範,我個人是深惡痛絕的,但是產品是這樣設計的,也只能是這樣做了。在這篇部落格中,我將結合網上的資料以及自己的使用經驗來實現一個底部選單,解決了很多網友提出的各種問題,在文章中,我只貼出部分的實現程式碼以及效果圖,免得佔用大量的篇幅,讓大家看的不爽,在最後我會給出整個demo的原始碼!!!
底部選單的設計
一般來說,底部選單是做多五個tab,這裡面我做了四個tab,比較符合需求,實現的方式主要有tabhost,直接TextView,RadioButton等,我在這裡使用的是RadioButton,覺得RadioButton比較簡單控制,又能很好的實現我們的需求,底部選單的activity_main.xml的程式碼如下:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<FrameLayout
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@+id/divide"
android:layout_alignParentTop="true">
</FrameLayout>
<View
android:id="@+id/divide"
android:layout_width ="match_parent"
android:layout_height="1dp"
android:layout_above="@+id/activity_group_radioGroup"
android:background="#cccccc"/>
<RadioGroup
android:id="@+id/activity_group_radioGroup"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:background="#ffffff"
android:checkedButton="@+id/order_process"
android:gravity="center"
android:orientation="horizontal"
android:paddingBottom="3dp"
android:paddingTop="3dp">
<RadioButton
android:id="@+id/order_process"
style="@style/main_tab_bottom"
android:layout_width="fill_parent"
android:layout_height="match_parent"
android:layout_weight="1.0"
android:drawableTop="@drawable/main_tab_1"
android:gravity="center"
android:text="訂單處理"/>
<RadioButton
android:id="@+id/order_query"
style="@style/main_tab_bottom"
android:layout_width="fill_parent"
android:layout_height="match_parent"
android:layout_weight="1.0"
android:checked="false"
android:drawableTop="@drawable/main_tab_2"
android:gravity="center"
android:text="訂單查詢"/>
<RadioButton
android:id="@+id/merchant_manager"
style="@style/main_tab_bottom"
android:layout_width="fill_parent"
android:layout_height="match_parent"
android:layout_weight="1.0"
android:checked="false"
android:drawableTop="@drawable/main_tab_3"
android:gravity="center"
android:text="門店管理"/>
<RadioButton
android:id="@+id/setting"
style="@style/main_tab_bottom"
android:layout_width="fill_parent"
android:layout_height="match_parent"
android:layout_weight="1.0"
android:checked="false"
android:drawableTop="@drawable/main_tab_4"
android:gravity="center"
android:text="設定"/>
</RadioGroup>
</RelativeLayout>
這個應該很好理解,就是在底部一個RadioGroup,內部放RadioButton來實現,上面放一個FrameLayout來放內容,這是xml部分。
Java程式碼控制Fragment的切換
在進行tab切換的過程中,我使用show()和hide()來處理,這樣可以儲存Fragment的狀態,核心程式碼如下
public void onCheckedChanged(RadioGroup group, int checkedId) {
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
Fragment fragment1 = fm.findFragmentByTag(fragment1Tag);
Fragment fragment2 = fm.findFragmentByTag(fragment2Tag);
Fragment fragment3 = fm.findFragmentByTag(fragment3Tag);
Fragment fragment4 = fm.findFragmentByTag(fragment4Tag);
if (fragment1 != null) {
ft.hide(fragment1);
}
if (fragment2 != null) {
ft.hide(fragment2);
}
if (fragment3 != null) {
ft.hide(fragment3);
}
if (fragment4 != null) {
ft.hide(fragment4);
}
switch (checkedId) {
case R.id.order_process:
if (fragment1 == null) {
fragment1 = new Fragment1();
ft.add(R.id.container, fragment1, fragment1Tag);
} else {
ft.show(fragment1);
}
break;
case R.id.order_query:
if (fragment2 == null) {
fragment2 = new Fragment2();
ft.add(R.id.container, fragment2, fragment2Tag);
} else {
ft.show(fragment2);
}
break;
case R.id.merchant_manager:
if (fragment3 == null) {
fragment3 = new Fragment3();
ft.add(R.id.container, fragment3,
fragment3Tag);
} else {
ft.show(fragment3);
}
break;
case R.id.setting:
if (fragment4 == null) {
fragment4 = new Fragment4();
ft.add(R.id.container, fragment4, fragment4Tag);
} else {
ft.show(fragment4);
}
break;
default:
break;
}
ft.commit();
}
});
切換的很完美,我們看下效果:
問題
1、上面的實現底部選單,能夠很好的實現Fragment的切換,還能夠儲存Fragment之前的狀態,但是有個很大的問題,就是,我們把app退到後臺,我們去玩其他的app,過一段時間回來,這個時候我們的app已經被銷燬,我們按多工鍵切換回來,發現介面上多個Fragment出現了重疊的情況,這是因為多個Fragment同時顯示了,出現了重疊的情況,解決的辦法如下:重寫Activity的onRestoreInstanceState方法
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
for (int i = 0; i < radioGroup.getChildCount(); i++) {
RadioButton mTab = (RadioButton) radioGroup.getChildAt(i);
FragmentManager fm = getSupportFragmentManager();
Fragment fragment = fm.findFragmentByTag((String) mTab.getTag());
FragmentTransaction ft = fm.beginTransaction();
if (fragment != null) {
if (!mTab.isChecked()) {
ft.hide(fragment);
}
}
ft.commit();
}
}
很好的解決了Fragment重疊的情況
2、如果在Fragment有操作toolbar的選單的情況,除了要在Fragment中設定setHasOptionsMenu(true);
之外,還需要Fragment中重寫onHiddenChanged方法:
@Override
public void onHiddenChanged(boolean hidden) {
super.onHiddenChanged(hidden);
if (!hidden) {
((AppCompatActivity) getActivity()).setSupportActionBar(mToolbar);
((AppCompatActivity)getActivity()).getSupportActionBar().setDisplayShowTitleEnabled(false);
setHasOptionsMenu(true);
}
}
不然的話,在恢復Fragment的時候會出現選單混亂的情況。
大功告成,大家有什麼問題或者建議請給我留言!!!
最後給出原始碼:下載