简单易用多功能Fragment架构

作者: Ch3r1sh | 来源:发表于2017-11-30 17:01 被阅读121次

    前言

    从Android3.0引入Fragment之后,日常开发中,业务组的同学实现各种界面总会用到Fragment进行实现.

    但是相应的使用Fragment对比单纯使用Activity的太多了,具体可以查看Fragment全解析系列

    为什么开发此库

    近一年主要在做React-Native,近期重构项目重写桥接了部分RN的组件,业务组的原生使用Fragment时比较混乱,因此将Fragment的使用操作进行封装.

    特性

    • 适用于单Activity+多Fragment或者多Activity+多Fragment
    • 使用于模块化,便于业务组的开发维护
    • 支持Tab类型界面一句话调用显示
    • 支持模块化流程式界面控制
    • 支持fragment配合ViewPager的懒加载
    • 支持Fragment动画入栈出栈的控制显示
    • 支持单独设置某一个Fragment的动画
    • 支持Fragment单个实例或多个实例
    • 支持回退栈BackStack管理
    • 支持类似Activity的startActivityForResult的回执信息
    • 支持参数传递并且回执

    动画设置

    方法 解释 默认值
    useAnim 是否使用Fragment动画 false
    enterAnim 入栈动画 R.animator.fragment_slide_left_enter
    exitAnim ---- R.animator.fragment_slide_left_exit
    popEnterAnim ---- R.animator.fragment_slide_right_enter
    popExitAnim 出栈动画 R.animator.fragment_slide_right_exit

    注意使用的时候使用属性动画,否则出栈动画会有显示异常。
    对于入栈动画和出栈动画只需要重写返回enterAnim和popExitAnim即可。

    下图的动画是设置了3秒的动画时间

    Anim.gif
    public class FlowModeActivity extends QuickActivity {
    
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.flowmode_activity);
    
            startFragment(StartFragment.class);
    
        }
    
       @Override
        public boolean useAnim() {
            return true;
        }
    
        @Override
        public int enterAnim() {
            return super.enterAnim();
        }
    
        @Override
        public int exitAnim() {
            return super.exitAnim();
        }
    
        @Override
        public int popEnterAnim() {
            return super.popEnterAnim();
        }
    
        @Override
        public int popExitAnim() {
            return super.popExitAnim();
        }
    
        @Override
        public int fragmentId() {
            return R.id.rootview;
        }
    
    }
    

    Tab类型(使用showFragment(XXX))

    Tab类型的UI界面很常见,一般我们使用Hide,Show的方式,对应Fragment首次添加是这样的

    FragmentManager manager = getSupportFragmentManager();  
        FragmentTransaction transaction = manager.beginTransaction();  
        transaction.add(R.id.fragment_container,fragment, tag);  //首次添加
        transaction.addToBackStack(tag);  
        transaction.commit();  
    

    在切换过程中

    transaction.hide(fragment);  //隐藏
    transaction.show(fragment); 
    transaction.commit();
    

    简单封装

    public void switchFragment(Fragment fragment, Fragment targetFragment) {  
        if (!to.isAdded()) {    // 先判断是否被add过  
            transaction.hide(from).add(R.id.content_frame, to).commit(); // 隐藏当前的fragment,add下一个到Activity中  
        } else {  
            transaction.hide(from).show(to).commit(); // 隐藏当前的fragment,显示下一个  
        }  
    }  
    

    使用起来还是过于繁琐,需要多次创建FragmentTransaction事物,现在你只需要一句话即可.
    Tab类型的只会存在一个fragment实例

    实例判断即可

    /**
         * Show a fragment.
         *
         * @param targetFragment fragment to display.
         * @param <T>            {@link QuickFragment}.
         */
        public final <T extends QuickFragment> void showFragment(T targetFragment) {
            try {
                QuickFragment showFragment = findFragmentByTag(targetFragment);
    
                if (showFragment == null) {
                    showFragment = targetFragment;
                    if (showFragment == null) {
                        return;
                    }
                }
                switchFragment(showFragment);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    

    Tab类型使用方式:

     showFragment(FragmentOne.class);
     showFragment(new FragmentOne());
    
    Tab.gif

    模块化流程式(使用startFragment(XXX))

    模块化流程式的Fragment一般用于模块或者流程,比如登录-注册-忘记密码等等,可以将其理解为用户模块,对页面采用Fragment处理进行流程控制化.着重于需要对Fragment的栈进行管理控制,模块化后的Fragment就像Activity一样使用

    模块流程式类型的允许存在一个fragment实例

    /**
         * Show a fragment.
         *
         * @param mCurrentFragment displaying fragment,default is mCurrentFragment
         * @param targetFragment   fragment to display.
         * @param stickyStack      sticky back stack.
         * @param requestCode      requestCode.
         * @param <T>              {@link QuickFragment}.
         */
        protected final <T extends QuickFragment> void startFragment(T mCurrentFragment, T targetFragment,
                                                                     boolean stickyStack, int requestCode) {
            FragmentTransaction fragmentTransaction = getFragmentTransaction();
            if (mCurrentFragment != null) {
                FragmentStackEntity thisStackEntity = mFragmentEntityMap.get(mCurrentFragment);
                if (thisStackEntity != null) {
                    if (thisStackEntity.isSticky) {
                        mCurrentFragment.onPause();
                        mCurrentFragment.onStop();
                        fragmentTransaction.hide(mCurrentFragment);
                    } else {
                        fragmentTransaction.remove(mCurrentFragment).commit();
                        fragmentTransaction.commitNow();
                        fragmentTransaction = getFragmentTransaction();
    
                        mFragmentEntityMap.remove(mCurrentFragment);
                        mFragmentStack.remove(mCurrentFragment);
                    }
                }
            }
    
            String fragmentTag = targetFragment.getClass().getSimpleName() + atomicInteger.incrementAndGet();
            fragmentTransaction.add(fragmentId(), targetFragment, fragmentTag);
            fragmentTransaction.addToBackStack(fragmentTag);
            fragmentTransaction.commit();
    
            FragmentStackEntity fragmentStackEntity = new FragmentStackEntity();
            fragmentStackEntity.isSticky = stickyStack;
            fragmentStackEntity.requestCode = requestCode;
            targetFragment.setStackEntity(fragmentStackEntity);
            mFragmentEntityMap.put(targetFragment, fragmentStackEntity);
    
            mFragmentStack.add(targetFragment);
        }
    
    FlowMode.gif

    Fragment之间Intent单独传参

    • 传递
     Bundle bundle = new Bundle();
                    bundle.putString("msg", "我爱你");
                    QuickFragment fragment = fragment(ArgumentFragment.class, bundle);
                    startFragment(fragment);
    
    • 接受
      Bundle bundle = getArguments();
            message = bundle.getString("msg");
    

    startFragmentForResult()回执信息

    • 请求
     startFragmentForResquest(CallBackFragment.class, 100);
    
    • 返回信息
      Bundle bundle = new Bundle();
                    bundle.putString("message", editText.getText().toString());
                    setResult(RESULT_OK, bundle);
                    finish();
    
    • 获取回执信息
    @Override
        public void onFragmentResult(int requestCode, int resultCode, @Nullable Bundle result) {
            switch (requestCode) {
                case 100: {
                    if (resultCode == RESULT_OK) {
                        String message = result.getString("message");
                        if (TextUtils.isEmpty(message)) {
                            Toast.makeText(activity, "没有返回信息", 1).show();
                        } else {
                            Toast.makeText(activity, message, 1).show();
                        }
                    } else if (resultCode == RESULT_CANCELED) {
                    }
                    break;
                }
    
                case 101: {
                    if (resultCode == RESULT_OK) {
                        String message = result.getString("message");
                        if (TextUtils.isEmpty(message)) {
                            Toast.makeText(activity, "没有返回信息", 1).show();
                        } else {
                            Toast.makeText(activity, message, 1).show();
                        }
                    } else if (resultCode == RESULT_CANCELED) {
                    }
                    break;
                }
            }
        }
    

    传递参数并且回执信息

    结合单独发送消息以及获取回执消息即可(参见DEMO)

    BackStack回退栈

    保存回退栈

    所谓保存回退栈意思为A-->B-->C,那么按返回键回来的时候会依次回到C-->B-->A

    startFragment(BackStackFragment1.class, true);
    

    不保存回退栈

    同样的A-->B-->C-->D,如果我们在启动的时候不保存B和C,那么按返回键回来会直接D-->A,中间的B,C将不会出现

    startFragment(BackStackFragment1.class, false);
    

    懒加载

    @Override
        protected void initLazy() {
            //懒加载设置值或者网络请求等
    //        textView.setText(content);
        }
    
        @Override
        protected void initNotLazy() {
    
        }
    

    如果是没有配合ViewPager使用,那么初始化请求设置等操作直接在initNotLazy执行,如果在initLazy执行界面将不会显示

    若有疑问,请在Github提交issue或者查看DEMO
    QuickFragmen地址

    相关文章

      网友评论

        本文标题:简单易用多功能Fragment架构

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