简单易用多功能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地址

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270

推荐阅读更多精彩内容