简单易用多功能Fragment架构

前言

从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地址

推荐阅读更多精彩内容