android 主頁底部選單tab切換標籤
雖然現在谷歌官方也提供了不少控制元件可解決這個效果,第三方也不少,也幾乎所有人都會實現這種效果,但本人仍想記錄一下。
這裡的實現是使用RadioGroup+FrameLayout實現,自己定義個FragmentTabAdapter,不使用viewpage。
這裡從簡單的開始吧!
首先tab欄的實現,定義選中和非選中的drawable大家都會的了所以這裡就不多說了,對於RadioButton的風格樣式肯定是不滿足需要的,所以進行下處理吧!先看程式碼,如下
------------------------------------------------ <style name="tabBarButton" parent="android:Widget.CompoundButton.RadioButton"> <item name="android:drawablePadding">0dp</item> <item name="android:button">@null</item> <item name="android:textSize">11dp</item> <!--部分機型,如三星N7100,不加padding會出現偏移,導致第一個左邊多出很多空白,最後一個靠邊--> <item name="android:padding">0dp</item> <item name="android:maxLines">1</item> <item name="android:gravity">center</item> <item name="android:layout_gravity">center</item> <item name="android:layout_weight">1.0</item> <item name="android:layout_width">0dp</item> <item name="android:layout_height">wrap_content</item> <item name="android:textColor">@color/selector_black_a1</item> </style> ---------------------------------------------
在佈局中只需設定drawableTop和text即可,如下程式碼(或者這兩個屬性直接在程式碼裡寫兩個陣列,進行for迴圈addView進去也是很方便的)
------------------------------------------------ <RadioButton style="@style/tabBarButton" android:drawableTop="@android:drawable/btn_star" android:text="第三方tool" /> -----------------------------------------------
佈局這些都是比較簡單的,剩下就是FragmentTabAdapter類了。
這裡介面卡需接受一下引數(或者也使用抽象類,一些資料外部使用的時候再實現)
1、List<Fragment> 該主頁需切換的幾個Fragment
2、RadioGroup 我們佈局中的RadioGroup,為其新增OnCheckedChangeListener
3、fragmentContentId,佈局中FrameLayout的id
4、FragmentActivity,這裡只是為了獲取FragmentManager,如果不是繼承FragmentActivity的,也可改為FragmentManager。這裡直接接收activity是為了以防有莫名的需求需要activity物件
所以構造方法如下:
------------------------------------------------
public FragmentTabAdapter(FragmentActivity fragmentActivity, List<Fragment> fragments, int fragmentContentId, RadioGroup rgs) {
this.fragments = fragments;
this.rgs = rgs;
this.fragmentActivity = fragmentActivity;
this.fragmentContentId = fragmentContentId;
this.cuurentCheckId = rgs.getCheckedRadioButtonId();
// 預設顯示第一頁
FragmentTransaction ft = fragmentActivity.getSupportFragmentManager().beginTransaction();
ft.add(fragmentContentId, fragments.get(0));
ft.commit();
rgs.setOnCheckedChangeListener(this);
}
------------------------------------------------
因為我們需要為RadioGroup 新增事件,所以直接就實現 RadioGroup.OnCheckedChangeListener介面了,主要是監聽RadioGroup改變選中view時,實時的改變顯示的Fragment,實現如下:
-----------------------------------------------
@Override
public void onCheckedChanged(RadioGroup radioGroup, int checkedId) {
for (int i = 0; i < rgs.getChildCount(); i++) {
if (rgs.getChildAt(i).getId() == checkedId) {
if (null == onRgsCheckedListener ||
!onRgsCheckedListener.onResCheckedChangedBefor(radioGroup, checkedId, i, cuurentCheckId, currentTab)) {
Fragment fragment = fragments.get(i);
FragmentTransaction ft = obtainFragmentTransaction(i);
getCurrentFragment().onPause(); // 暫停當前tab
if (fragment.isAdded()) {
fragment.onResume(); // 啟動目標tab的onResume()
} else {
ft.add(fragmentContentId, fragment);
}
showTab(i); // 顯示目標tab
ft.commit();
cuurentCheckId = checkedId;
// 如果設定了切換tab額外功能功能介面
if (null != onRgsCheckedListener) {
onRgsCheckedListener.onRgsCheckedChanged(radioGroup, checkedId, i);
}
}
}
}
}
------------------------------------------------
程式碼中的showTab()方法則是控制哪個Fragment顯示的方法:
-----------------------------------------------
/**
* 切換tab
*
* @param idx
*/
private void showTab(int idx) {
for (int i = 0; i < fragments.size(); i++) {
Fragment fragment = fragments.get(i);
FragmentTransaction ft = obtainFragmentTransaction(idx);//我們加個切換動畫
if (idx == i) {
ft.show(fragment);
} else {
ft.hide(fragment);
}
ft.commit();
}
currentTab = idx; // 更新目標tab為當前tab
}
/**
* 獲取一個帶動畫的FragmentTransaction
*
* @param index
* @return
*/
private FragmentTransaction obtainFragmentTransaction(int index) {
FragmentTransaction ft = fragmentActivity.getSupportFragmentManager().beginTransaction();
// 設定切換動畫
if (index > currentTab) {
ft.setCustomAnimations(R.anim.slide_left_in, R.anim.slide_left_out);
} else {
ft.setCustomAnimations(R.anim.slide_right_in, R.anim.slide_right_out);
}
return ft;
}
------------------------------------------------
至此我們的介面卡已經完成了,有人會注意到在onCheckedChanged方法中好像有預留了個介面,是的,這邊預留了個介面,以滿足特殊需求的需要,如小紅點,登入才可切換,雙擊滾到頂部等,這裡不想強制實現所有的方法,所以直接寫成了空實現的類,可據需繼承實現,程式碼如下:
/**
* 切換tab額外功能功能介面
*/
public static class OnRgsCheckedListener {
/**改變tab之後
* @param radioGroup
* @param checkedId 選擇的RadioButton的id
* @param index 選擇的下標
*/
void onRgsCheckedChanged(RadioGroup radioGroup, int checkedId, int index) {
//RadioGroup 改變選中View之後呃回撥,用於
}
/**在改變tab之前
* @param radioGroup
* @param checkedId 選擇的RadioButton的id
* @param index 選擇的下標
* @param preCheckedId 當前的RadioButton的id
* @param preIndex 當前的下標
* @return
*/
boolean onResCheckedChangedBefor(RadioGroup radioGroup, int checkedId,
int index, int preCheckedId, int preIndex) {
//如某些子頁面需要登入後才可訪問,即可在此攔截,返回true則不進行頁面切換
return false;
}
}
另外順便在此記一下,這中實現,當我們app存在bug,導致app閃退自動重啟時,我們的MainActivity是會被回收重新生成呼叫Oncreate方法的,而系統卻預設把fragment快取了,沒有回收,所以但app閃退自動重啟後你會發現會有兩個以上的Fragment會重疊在一起,我的解決方法是在oncreate方法中先將存在的Fragment全部移除掉,程式碼如下:
//避免activity蹦潰回收,fragment沒回收,activity重啟導致fragment重疊現象,
List<Fragment> temF = getSupportFragmentManager().getFragments();
if (temF != null) {
for (Fragment f : temF) {
removeFragment(f);
}
}
原文地址:http://blog.csdn.net/lanqi_x/article/details/78039324