徹底解決Fragment重疊的問題
阿新 • • 發佈:2018-12-31
在佈局應用一級頁面時很多App都會採取BottomBar + Fragment切換來構建。一般Fragment會使用FragmentManager管理,就是在一個FrameLayout構成的ContentView上做show和hide,
在這裡有一個問題需要注意,在這種有多個按鈕處於一個螢幕可以快速切換Fragment的UI佈局下,不要使用add和replace去切換fragment,使用show和hide去切換是最好的選擇,因為show和hide本質上是在控制Fragment中View的Visiblity,而執行replace則會觸發fragment的detach()函式與Activity解除關聯,如果此時使用者快速點選,在detach還沒執行完就執行attach(),很容易產生IllegalStateException:no host;應用直接崩潰。
使用show和hide很容易出現的問題就是承載Fragmen的Activity在旋轉螢幕,資源不足被釋放資源然後恢復重建這些情況下,被承載的Fragment在恢復時沒能正確恢復狀態,然後全部都顯示了出來。解決這個問題的核心就是在Fragment恢復時全部隱藏,然後根據當前顯示的Fragment的TAG顯示Fragment。
本來想把這段程式碼封裝成一個Activity基類,後面想想應用一級的需求頁面千奇百怪,封裝了也沒什麼通用性,就在這裡記錄一下,分享一下順便備忘了=。=
上程式碼:
public abstract class MainActivity extends BaseActivity { private static final String SAVED_CURRENT_ID = "currentId"; public static final List<String> PAGE_TAGS = new ArrayList<>(); private List<Class<? extends BaseFragment>> fragmentClasses = Arrays.asList(HomeFragment.class, MoreFragment.class, ProfileFragment.class); //自定義的Fragment,主要目的是在初始化時能夠通過迴圈初始化,與重建時的恢復統一 private List<Fragment> fragments = new ArrayList<>(); private FragmentManager mFragmentManager; private int currentId = 0; @Override public void onCreate(Bundle savedInstanceState, PersistableBundle persistentState) { super.onCreate(savedInstanceState, persistentState); setContentView(R.layout.activity_main); initFragments(); } private void initFragments(Bundle savedInstanceState) { mFragmentManager = getSupportFragmentManager(); for(int i = 0; i < fragments.size(); i++) { fragments.set(i, mFragmentManager.findFragmentByTag(PAGE_TAGS.get(i))); if(fragments.get(i) == null) { try { fragments.set(i,fragmentClasses.get(i).newInstance()); } catch (Exception e) { e.printStackTrace(); } } //先重置所有fragment的狀態為隱藏,徹底解決重疊問題 if(fragments.get(i).isAdded()) { mFragmentManager.beginTransaction() .hide(fragments.get(i)) .commitAllowingStateLoss(); } } if(savedInstanceState != null) { int cachedId = savedInstanceState.getInt(SAVED_CURRENT_ID, 0); if(cachedId >= 0 && cachedId <= 4) { currentId = cachedId; } } switchFragment(currentId, false); } @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putInt(SAVED_CURRENT_ID, currentId); } private void switchFragment(int index) { switchFragment(index, true); } private void switchFragment(int index, boolean anim) { /* Fragment 切換 */ FragmentTransaction transaction = mFragmentManager.beginTransaction(); if(anim) { //顯示切換動畫 if(index > currentId) { transaction.setCustomAnimations(R.anim.slide_right_in, R.anim.slide_left_out); } else { transaction.setCustomAnimations(R.anim.slide_left_in, R.anim.slide_right_out); } } if(fragments.get(index).isAdded()) { transaction.hide(fragments.get(currentId)); transaction.show(fragments.get(index)); } else { transaction.hide(fragments.get(currentId)); transaction.add(getFragmentContainerLayoutRes(), fragments.get(index), PAGE_TAGS.get(index)); transaction.show(fragments.get(index)); } transaction.setTransitionStyle(FragmentTransaction.TRANSIT_FRAGMENT_FADE); transaction.commitAllowingStateLoss(); currentId = index; } }