美文网首页
定制的Fragment导航器,替换ft.replace(mCon

定制的Fragment导航器,替换ft.replace(mCon

作者: Perston | 来源:发表于2020-05-15 07:05 被阅读0次

    1.对destination.json通过GsonFormat进行变成对象
    2.编写AppConfig工具类对destination.json解释成HashMap
    3.创建FixFragmentNavigator
    4.创建NavGraphBuilder

    1.对destination.json通过GsonFormat进行变成对象

    image.png
    {
      "main/tabs/home": {
        "isFragment": true,
        "asStarter": true,
        "needLogin": false,
        "pageUrl": "main/tabs/home",
        "className": "com.mooc.ppjoke.ui.home.HomeFragment",
        "id": 946010952
      }
    }
    
    public class Destination {
        /**
         * isFragment : true
         * asStarter : true
         * needLogin : false
         * pageUrl : main/tabs/home
         * className : com.mooc.ppjoke.ui.home.HomeFragment
         * id : 946010952
         */
        public boolean isFragment;
        public boolean asStarter;
        public boolean needLogin;
        public String pageUrl;
        public String className;
        public int id;
    }
    

    2.编写AppConfig工具类对destination.json解释成HashMap

    import android.content.res.AssetManager;
    import com.alibaba.fastjson.JSON;
    import com.alibaba.fastjson.TypeReference;
    import com.mooc.libcommon.global.AppGlobals;
    import com.mooc.ppjoke.model.Destination;
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.util.Collections;
    import java.util.Comparator;
    import java.util.HashMap;
    
    public class AppConfig {
        private static HashMap<String, Destination> sDestConfig;
    
        public static HashMap<String, Destination> getDestConfig() {
            if (sDestConfig == null) {
                String content = parseFile("destination.json");
                sDestConfig = JSON.parseObject(content, new TypeReference<HashMap<String, Destination>>() {
                });
            }
            return sDestConfig;
        }
    
        private static String parseFile(String fileName) {
            AssetManager assets = AppGlobals.getApplication().getAssets();
            InputStream is = null;
            BufferedReader br = null;
            StringBuilder builder = new StringBuilder();
            try {
                is = assets.open(fileName);
                br = new BufferedReader(new InputStreamReader(is));
                String line = null;
                while ((line = br.readLine()) != null) {
                    builder.append(line);
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    if (is != null) {
                        is.close();
                    }
                    if (br != null) {
                        br.close();
                    }
                } catch (Exception e) {
    
                }
            }
    
            return builder.toString();
        }
    }
    

    3.创建FixFragmentNavigator

    /**
     * 定制的Fragment导航器,替换ft.replace(mContainerId, frag);为 hide()/show()
     */
    @Navigator.Name("fixfragment")
    public class FixFragmentNavigator extends FragmentNavigator {
        private static final String TAG = "FixFragmentNavigator";
        private Context mContext;
        private FragmentManager mManager;
        private int mContainerId;
    
        public FixFragmentNavigator(@NonNull Context context, @NonNull FragmentManager manager, int containerId) {
            super(context, manager, containerId);
            mContext = context;
            mManager = manager;
            mContainerId = containerId;
        }
    
        @Nullable
        @Override
        public NavDestination navigate(@NonNull Destination destination, @Nullable Bundle args, @Nullable NavOptions navOptions, @Nullable Navigator.Extras navigatorExtras) {
            if (mManager.isStateSaved()) {
                Log.i(TAG, "Ignoring navigate() call: FragmentManager has already"
                        + " saved its state");
                return null;
            }
            String className = destination.getClassName();
            if (className.charAt(0) == '.') {
                className = mContext.getPackageName() + className;
            }
            //android.fragment.app.homefragment   homefragment
            String tag = className.substring(className.lastIndexOf(".") + 1);
            Fragment frag = mManager.findFragmentByTag(tag);
            if (frag == null) {
                frag = instantiateFragment(mContext, mManager,
                        className, args);
            }
            frag.setArguments(args);
            final FragmentTransaction ft = mManager.beginTransaction();
    
            int enterAnim = navOptions != null ? navOptions.getEnterAnim() : -1;
            int exitAnim = navOptions != null ? navOptions.getExitAnim() : -1;
            int popEnterAnim = navOptions != null ? navOptions.getPopEnterAnim() : -1;
            int popExitAnim = navOptions != null ? navOptions.getPopExitAnim() : -1;
            if (enterAnim != -1 || exitAnim != -1 || popEnterAnim != -1 || popExitAnim != -1) {
                enterAnim = enterAnim != -1 ? enterAnim : 0;
                exitAnim = exitAnim != -1 ? exitAnim : 0;
                popEnterAnim = popEnterAnim != -1 ? popEnterAnim : 0;
                popExitAnim = popExitAnim != -1 ? popExitAnim : 0;
                ft.setCustomAnimations(enterAnim, exitAnim, popEnterAnim, popExitAnim);
            }
    
            List<Fragment> fragments = mManager.getFragments();
            for (Fragment fragment : fragments) {
                ft.hide(fragment);
            }
            if (!frag.isAdded()) {
                ft.add(mContainerId, frag, tag);
            }
            ft.show(frag);
            //ft.replace(mContainerId, frag);
            ft.setPrimaryNavigationFragment(frag);
    
            final @IdRes int destId = destination.getId();
            ArrayDeque<Integer> mBackStack = null;
            try {
                Field field = FragmentNavigator.class.getDeclaredField("mBackStack");
                field.setAccessible(true);
                mBackStack = (ArrayDeque<Integer>) field.get(this);
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
    
            final boolean initialNavigation = mBackStack.isEmpty();
            // TODO Build first class singleTop behavior for fragments
            final boolean isSingleTopReplacement = navOptions != null && !initialNavigation
                    && navOptions.shouldLaunchSingleTop()
                    && mBackStack.peekLast() == destId;
    
            boolean isAdded;
            if (initialNavigation) {
                isAdded = true;
            } else if (isSingleTopReplacement) {
                // Single Top means we only want one instance on the back stack
                if (mBackStack.size() > 1) {
                    // If the Fragment to be replaced is on the FragmentManager's
                    // back stack, a simple replace() isn't enough so we
                    // remove it from the back stack and put our replacement
                    // on the back stack in its place
                    mManager.popBackStack(
                            generateBackStackName(mBackStack.size(), mBackStack.peekLast()),
                            FragmentManager.POP_BACK_STACK_INCLUSIVE);
                    ft.addToBackStack(generateBackStackName(mBackStack.size(), destId));
                }
                isAdded = false;
            } else {
                ft.addToBackStack(generateBackStackName(mBackStack.size() + 1, destId));
                isAdded = true;
            }
            if (navigatorExtras instanceof Extras) {
                Extras extras = (Extras) navigatorExtras;
                for (Map.Entry<View, String> sharedElement : extras.getSharedElements().entrySet()) {
                    ft.addSharedElement(sharedElement.getKey(), sharedElement.getValue());
                }
            }
            ft.setReorderingAllowed(true);
            ft.commit();
            // The commit succeeded, update our view of the world
            if (isAdded) {
                mBackStack.add(destId);
                return destination;
            } else {
                return null;
            }
        }
    
        private String generateBackStackName(int backStackindex, int destid) {
            return backStackindex + "-" + destid;
        }
    }
    
    

    4.创建NavGraphBuilder

    
    import android.content.ComponentName;
    
    import androidx.fragment.app.FragmentActivity;
    import androidx.fragment.app.FragmentManager;
    import androidx.navigation.ActivityNavigator;
    import androidx.navigation.NavController;
    import androidx.navigation.NavGraph;
    import androidx.navigation.NavGraphNavigator;
    import androidx.navigation.NavigatorProvider;
    import androidx.navigation.fragment.FragmentNavigator;
    
    import com.mooc.libcommon.global.AppGlobals;
    import com.mooc.ppjoke.navigator.FixFragmentNavigator;
    import com.mooc.ppjoke.model.Destination;
    
    import java.util.HashMap;
    import java.util.Iterator;
    
    public class NavGraphBuilder {
        public static void build(FragmentActivity activity, FragmentManager childFragmentManager, NavController controller, int containerId) {
            NavigatorProvider provider = controller.getNavigatorProvider();
    
            //NavGraphNavigator也是页面路由导航器的一种,只不过他比较特殊。
            //它只为默认的展示页提供导航服务,但真正的跳转还是交给对应的navigator来完成的
            NavGraph navGraph = new NavGraph(new NavGraphNavigator(provider));
    
            //FragmentNavigator fragmentNavigator = provider.getNavigator(FragmentNavigator.class);
            //fragment的导航此处使用我们定制的FixFragmentNavigator,底部Tab切换时 使用hide()/show(),而不是replace()
            FixFragmentNavigator fragmentNavigator = new FixFragmentNavigator(activity, childFragmentManager, containerId);
            provider.addNavigator(fragmentNavigator);
            ActivityNavigator activityNavigator = provider.getNavigator(ActivityNavigator.class);
            HashMap<String, Destination> destConfig = AppConfig.getDestConfig();
            Iterator<Destination> iterator = destConfig.values().iterator();
            while (iterator.hasNext()) {
                Destination node = iterator.next();
                if (node.isFragment) {
                    FixFragmentNavigator.Destination destination = fragmentNavigator.createDestination();
                    destination.setId(node.id);
                    destination.setClassName(node.className);
                    destination.addDeepLink(node.pageUrl);
                    navGraph.addDestination(destination);
                } else {
                    ActivityNavigator.Destination destination = activityNavigator.createDestination();
                    destination.setId(node.id);
                    destination.setComponentName(new ComponentName(AppGlobals.getApplication().getPackageName(), node.className));
                    destination.addDeepLink(node.pageUrl);
                    navGraph.addDestination(destination);
                }
    
                //给APP页面导航结果图 设置一个默认的展示页的id
                if (node.asStarter) {
                    navGraph.setStartDestination(node.id);
                }
            }
    
            controller.setGraph(navGraph);
        }
    }
    
    

    相关文章

      网友评论

          本文标题:定制的Fragment导航器,替换ft.replace(mCon

          本文链接:https://www.haomeiwen.com/subject/nykqohtx.html