Activity持有多个Fragment的跳转和回退实现方案

现在大多使用Fragment的场景有两种,一种是一个APP只有一个Activity+很多Fragment。另一种是APP中的每一个模块是一个Activity + 多个Fragment。最近需要用到Fragment来替代部分Activity。所以思考一下有什么方案。

实现的需求
  • Fragment 能像Activity那样有一个栈,然后跳转的时候会把Fragment加入到栈中,按返回键的时候能按顺序回退栈中的Fragment。
  • 退回到第一个Fragment的时候再按返回键就finish Activity。
  • 在跳转的时候和回退的时候能切换标题。
  • 在任意的Fragment中都有返回第一个Fragment的方法。

设计是这样的,首先定义一个接口:

public interface IFragmentCallBack {
    /**
     * 从一个Fragment 跳到另一个Fragment
     *
     * @param tag
     * @param current
     */
    void jump(String tag, BaseFragment current);

    /**
     * 返回第一个Fragment
     */
    void home();
}

定义一个BaseFragmentActivity实现这个接口,在onCreate方法中:

//处理异常退出恢复情况
        if (savedInstanceState != null) {
            List<Fragment> fragments = getSupportFragmentManager().getFragments();
            if (fragments != null && fragments.size() > 0) {
                boolean showFlag = false;
                FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
                for (int i = fragments.size() - 1; i >= 0; i--) {
                    Fragment fragment = fragments.get(i);
                    if (fragment != null) {
                        if (!showFlag) {
                            ft.show(fragments.get(i));
                            showFlag = true;
                        } else {
                            ft.hide(fragments.get(i));
                        }
                    }
                }
                ft.commit();
            }
        }

上面代码是处理Activity异常退出时恢复Fragment并且防止Fragment显示重叠的。

实现的接口的方法中,有home()jump(),home的主要用能是跳回第一个Fragment,jump是用来通过tag跳转Fragment的,

home 实现如下:

@Override
    public void home() {
        while (getSupportFragmentManager().getBackStackEntryCount() != 1) {
            getSupportFragmentManager().popBackStackImmediate();
        }
    }

jump 实现如下

@Override
    public void jump(String tag, BaseFragment current) {
        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
        HashMap<String, FragmentModule> modules = getFragmentModule();
        BaseFragment target = (BaseFragment) getSupportFragmentManager().findFragmentByTag(tag);
        if (target == null) {
            target = modules.get(tag).getFragment();
            transaction.hide(current)
                    .add(getContentId(), target, tag)
                    .addToBackStack(null)
                    .commit();
        } else {
            transaction.hide(current).show(target).commit();
        }
        setTitle(modules.get(tag).getTitle());
    }

这里使用了addshowhide方法,把Fragment添加到BackStack中,方便后面回退。上面使用了FragmentModulegetFragmentModulegetContentIdgetFragmentModule是抽象方法需要子类自己实现,getContentId也是抽象的,用于提供显示Framgent的布局id。

FragmentModule:

public class FragmentModule {
    public BaseFragment fragment;
    public String title;

    public FragmentModule(BaseFragment fragment, String title) {
        this.fragment = fragment;
        this.title = title;
    }

    public BaseFragment getFragment() {
        return fragment;
    }

    public String getTitle() {
        return title;
    }
}

需要添加回退功能。


    /**
     * 后退的时候按栈回退
     */
    @Override
    public void onBackPressed() {
        if (getSupportFragmentManager().getBackStackEntryCount() != 1) {
            getSupportFragmentManager().popBackStackImmediate();
        } else {
            super.onBackPressed();
        }
    }

回退的时候使用popBackStackImmediate方法出栈,注意这里不能使用popBackStack 否则 getBackStackEntryCount可能返回不正确的值。

接下来需要设置页面默认的Fragment,也就是第一个Fragment ,在onCreate中调用:

 FragmentModule defaultModule = getDefaultModule();
        setTitle(defaultModule.getTitle());
        getSupportFragmentManager().beginTransaction().add(getContentId(), defaultModule.getFragment(),             
        tag).addToBackStack(null).commit();

getDefaultModule 是一个抽象方法,用于返回默认的Fragment

上面基本上就搭建完毕。

使用的时候,Activity继承BaseFragmentActivity ,然后实现getDefaultMoudle()getContentIdgetFragmentModule 方法

  • getContentId返回布局的ID,Fragment会在该布局中显示
  • getFragmentModule返回一个HashMapkeyfragmenttag,值为FragmentModule
  • getDefaultMoudle直接new 一个FragmentModule即可。

最后,Fragment需要提供一个注入IFragmentCallback的构造方法。然后在Fragment中调用 callback.jump(tag,this)就可以跳转了,callback.home()可以回到第一个页面。

如果回退的时候需要改变标题需要重写Fragment的onHiddenChanged(boolean hidden)方法。

如果这些Fragment中还需要嵌套的话,比如一个Fragment(A)里面有ViewPager,ViewPager中又嵌套了几个Fragment的话,则A在调度ViewPager中的Fragment的时候,需要使用getChildFragmentManager,不能直接getSupportFragmentManager ,否则会出现Fragment重叠的问题。

这种方案没有在Fragment需要加载刷新大量数据下实现过,应用于登陆、注册这些静态模块没有问题,如果要使用在复杂场景下,可能会出现未知的坑~~~~

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值