package com.example.stackmasterdetailfrag; import android.support.annotation.NonNull; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentTransaction; import com.example.stackmasterdetailfrag.application.Path; import com.example.stackmasterdetailfrag.paths.MasterDetailPath; import com.example.stackmasterdetailfrag.paths.NoDetailsPath; import com.zhuinden.simplestack.StateChange; /** * Created by Zhuinden on 2017.02.12.. */ public class MasterDetailFragmentStateChanger { private final FragmentManager fragmentManager; private final int masterContainerId; private final int detailContainerId; public MasterDetailFragmentStateChanger(FragmentManager fragmentManager, int masterContainerId, int detailContainerId) { this.fragmentManager = fragmentManager; this.masterContainerId = masterContainerId; this.detailContainerId = detailContainerId; } public void handleStateChange(StateChange stateChange) { MasterDetailPath topKey = stateChange.topNewState(); Path masterKey; Path detailKey = NoDetailsPath.create(); if(!topKey.isMaster()) { detailKey = topKey; masterKey = topKey.getMaster(); } else { masterKey = topKey; } Fragment masterFragment = removeToDetachFragment(stateChange, masterKey); Fragment detailFragment = removeToDetachFragment(stateChange, detailKey); FragmentTransaction fragmentTransaction = beginFragmentTransaction(stateChange); if(!topKey.isMaster()) { removeFragment(fragmentTransaction, NoDetailsPath.create()); } for(Object _previousKey : stateChange.getPreviousState()) { Path previousKey = (Path) _previousKey; if(!stateChange.getNewState().contains(_previousKey)) { removeFragment(fragmentTransaction, previousKey); } else { if(!previousKey.equals(masterKey) && !previousKey.equals(detailKey)) { detachFragment(fragmentTransaction, previousKey); } } } Path previousTop = stateChange.topPreviousState(); // remove outlying master if(previousTop != null && (previousTop instanceof MasterDetailPath)) { MasterDetailPath previousMasterDetailTop = (MasterDetailPath) previousTop; if(!previousMasterDetailTop.isMaster() && !stateChange.getNewState() .contains(previousMasterDetailTop) && !stateChange.getNewState() .contains(previousMasterDetailTop.getMaster()) && !stateChange.<MasterDetailPath>topNewState().getMaster() .equals(previousMasterDetailTop.getMaster())) { Fragment previousMaster = fragmentManager.findFragmentByTag(previousMasterDetailTop.getMaster().getFragmentTag()); if(previousMaster != null) { fragmentTransaction.remove(previousMaster); } } } for(Object _newKey : stateChange.getNewState()) { Path newKey = (Path) _newKey; if(!newKey.equals(masterKey) && !newKey.equals(detailKey)) { detachFragment(fragmentTransaction, newKey); } } reattachRemovedFragment(masterFragment, fragmentTransaction, masterKey, masterContainerId); reattachRemovedFragment(detailFragment, fragmentTransaction, detailKey, detailContainerId); fragmentTransaction.commitNow(); } private void detachFragment(FragmentTransaction fragmentTransaction, Path key) { Fragment fragment = fragmentManager.findFragmentByTag(key.getFragmentTag()); if(fragment != null) { fragmentTransaction.detach(fragment); } } private void removeFragment(FragmentTransaction fragmentTransaction, Path path) { Fragment fragment = fragmentManager.findFragmentByTag(path.getFragmentTag()); if(fragment != null) { fragmentTransaction.remove(fragment); } } private void reattachRemovedFragment(Fragment fragment, FragmentTransaction fragmentTransaction, Path key, int containerId) { if(fragment == null) { fragment = key.createFragment(); } if(!fragment.isAdded() || (fragment.isDetached() || fragment.getView() == null)) { fragmentTransaction.add(containerId, fragment, key.getFragmentTag()); } } private Fragment removeToDetachFragment(StateChange stateChange, Path key) { Fragment fragment = fragmentManager.findFragmentByTag(key.getFragmentTag()); if(fragment != null && (fragment.isDetached() || fragment.getView() == null)) { FragmentTransaction fragmentTransaction = beginFragmentTransaction(stateChange); Fragment.SavedState savedState = fragmentManager.saveFragmentInstanceState(fragment); fragmentTransaction.remove(fragment); fragmentTransaction.commitNow(); fragment.setInitialSavedState(savedState); } return fragment; } @NonNull private FragmentTransaction beginFragmentTransaction(StateChange stateChange) { FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); fragmentTransaction.disallowAddToBackStack(); if(stateChange.getDirection() == StateChange.FORWARD) { fragmentTransaction.setCustomAnimations(R.anim.slide_in_from_right, R.anim.slide_out_to_left); } else if(stateChange.getDirection() == StateChange.BACKWARD) { fragmentTransaction.setCustomAnimations(R.anim.slide_in_from_left, R.anim.slide_out_to_right); } return fragmentTransaction; } }