我見過很多種裆操,寫也過很多種 - 首頁管理 Fragment ,這里我覺得有必要整理一下思路腰湾,為依然不是很順手的朋友提供下思路
1. Fragment 切換方式
首頁的 Fragment 是要求無縫切換的勤家,換言之就是不能卡健民,要一瞬間完成狮荔,有時產(chǎn)品還要加上一點小動畫效果
這里我們推薦 show/hide 這套組合,我們不用維護(hù) currentFragment 介粘,邏輯復(fù)雜轴合, 還容易出 bug ,最好的思路是遍歷 FragmentManager 碗短,看看誰當(dāng)前顯示者受葛,然后 hind,show 我們想要的就好偎谁,簡單干凈
@Override
protected void initListener() {
super.initListener();
navigationView.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_library:
switchFragment(libraryFragment);
break;
case R.id.menu_welfare:
if (welfareFragment == null) {
welfareFragment = new WelfareFragment();
}
switchFragment(welfareFragment);
break;
case R.id.menu_my:
if (myFragment == null) {
myFragment = new MyFragment();
}
switchFragment(myFragment);
break;
}
return true;
}
});
private void switchFragment(Fragment fragment) {
List<Fragment> fragments = fm.getFragments();
for (Fragment f : fragments) {
if (!f.equals(fragment) && !f.isHidden()) {
fm.beginTransaction().hide(f).commit();
}
}
if (fragment.isAdded()) {
fm.beginTransaction().show(fragment).commit();
} else {
fm.beginTransaction().add(R.id.container, fragment).commit();
}
}
2. 第一個 Fragment 的處理
第一個 Fragment 我們直接在 onCreate 中初始化总滩,addFragment 進(jìn)去
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(bindLayout());
libraryFragment = new LibraryFragment();
addFragment(R.id.rootView, libraryFragment);
}
private void addFragment(int layoutID, Fragment fragment) {
if (fragment.isAdded()) {
fm.beginTransaction().show(fragment).commit();
} else {
fm.beginTransaction().add(layoutID, fragment).commit();
}
}
3. 首頁異常關(guān)閉處理
AC 若是由系統(tǒng)回收,屏幕旋轉(zhuǎn)或是異常關(guān)閉巡雨,會保存 app 中各種信息的闰渔,AC 堆棧數(shù)據(jù),F(xiàn)ragment 堆棧數(shù)據(jù)铐望。這里說首頁冈涧,首頁要是這樣被關(guān)閉然后由系統(tǒng)再起來,那么就會恢復(fù)之前我們在首頁添加的所有 Fragment 頁面正蛙,并且這樣頁面都在顯示督弓,也就是所謂的穿透 bug
樣子大概是這樣的:
若是這種情況,我們需要處理 onSaveInstanceState 和 onRestoreInstanceState 2個方法
3.1 onCreate 里面 savedInstanceState == null乒验,表示正常啟動
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//初始化
init();
//根據(jù)傳入的Bundle對象判斷Activity是正常啟動還是銷毀重建
if(savedInstanceState == null){
//設(shè)置第一個Fragment默認(rèn)選中
setFragment(0);
}
}
3.2 維護(hù)一個 fragmentId 或是一個 tag(可選項)
3.3 onSaveInstanceState 中保存當(dāng)前顯示的 Fragment 標(biāo)記愚隧,這個可以是上面自己記錄的fragmentId ,也可以遍歷 FragmentManage锻全,找到其中 !isHidden()狂塘,獲取其 TAG
@Override
protected void onSaveInstanceState(Bundle outState) {
//通過onSaveInstanceState方法保存當(dāng)前顯示的fragment
outState.putInt("fragment_id",fragmentId);
super.onSaveInstanceState(outState);
}
3.4 onRestoreInstanceState 獲取所有的 Fragment ,然后顯示標(biāo)記的 鳄厌,hidden 其他的
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
FragmentManager mFragmentManager = getSupportFragmentManager();
//通過FragmentManager獲取保存在FragmentTransaction中的Fragment實例
mClothesFragment = (ClothesFragment)mFragmentManager
.findFragmentByTag("clothes_fragment");
mFoodFragment = (FoodFragment)mFragmentManager
.findFragmentByTag("food_fragment");
mHotelFragment = (HotelFragment)mFragmentManager
.findFragmentByTag("hotel_fragment");
//恢復(fù)銷毀前顯示的Fragment
setFragment(savedInstanceState.getInt("fragment_id"));
}
具體可以參考:
4. 配合 navigationBar 的優(yōu)秀寫法
這里使用的是開源 navigationBar : BottomNavigation
class HomeActivity : AppCompatActivity(){
private var lastSelectedPosition = 0
override fun onTabSelected(position: Int) {
lastSelectedPosition = position
replaceFragments(position)
}
private fun replaceFragments(position: Int) {
supportFragmentManager.beginTransaction().apply {
when (position) {
0 -> replace(R.id.home_activity_frag_container, fragment1)
1 -> replace(R.id.home_activity_frag_container, fragment2)
2 -> replace(R.id.home_activity_frag_container, fragment3)
3 -> replace(R.id.home_activity_frag_container, fragment4)
4 -> replace(R.id.home_activity_frag_container, fragment5)
else -> replace(R.id.home_activity_frag_container, fragment6)
}
}.commitAllowingStateLoss()
}
}
這個寫法看著很干凈荞胡,當(dāng)然 replace 大家自己改改,換個方法
5. 其他
有位簡 友分享了自己的 fragment 切換代碼了嚎,只不過這個朋友比我們更對自己狠了一些泪漂,他想看看代碼通過設(shè)計能減到多少,玉石有了一篇: 記錄一次代碼演變過程——35行變24行新思,其實很不錯的窖梁,大家沒事都看看,當(dāng)我們平時對自己嚴(yán)要求之后都會有些閃光點的夹囚,記下來纵刘,因為你很快機(jī)會忘