嵌套片段和后栈

时间:2012-12-04 15:26:09

标签: android android-fragments android-nested-fragment

Back Stack是否支持与Android中嵌套片段的交互?

如果是的话,我做错了什么?在我的实现中,后退按钮完全忽略了我将此事务添加到后台堆栈的事实。我希望这不是因为嵌套片段的问题,而是我做错了什么。

以下代码位于我的一个片段中,用于将新片段与当前显示的嵌套片段交换:

     MyFragment fragment = new MyFragment();
     FragmentTransaction ft = getChildFragmentManager().beginTransaction();
     ft.setCustomAnimations(R.animator.slide_in_from_right, R.animator.slide_out_left, R.animator.slide_in_from_left, R.animator.slide_out_right);
     ft.addToBackStack(null);
     ft.replace(R.id.myFragmentHolder, fragment);
     ft.commit();

4 个答案:

答案 0 :(得分:30)

我有同样的问题,我想嵌套片段,并为每个嵌套片段保留一个后栈。

但是......似乎这个案例不是由v4支持库处理的。在库中的FragmentActivity代码中,我可以找到:

public void onBackPressed() {
    if (!mFragments.popBackStackImmediate()) {
        finish();
    }
}

mFragments代表活动的FragmentManager,但似乎这个管理器不会将pop“传播”给子管理器。 解决方法是手动调用子管理器上的popBackStackImmediate(),就像从FragmentActivity继承的活动中一样:

private Fragment myFragmentContainer;

    @Override
    public void onBackPressed() {
            if (!myFragmentContainer.getChildFragmentManager().popBackStackImmediate()) {
                finish(); //or call the popBackStack on the container if necessary
            }
    }

可能有更好的方式和更自动化的方式,但根据我的需要,它是好的。

答案 1 :(得分:4)

在我目前的项目中,我们有多个“嵌套层”,所以我想出了以下解决方法,只为顶级片段管理器自动弹出backstack:

@Override
public void onBackPressed() {
    SparseArray<FragmentManager> managers = new SparseArray<>();
    traverseManagers(getSupportFragmentManager(), managers, 0);
    if (managers.size() > 0) {
        managers.valueAt(managers.size() - 1).popBackStackImmediate();
    } else {
        super.onBackPressed();
    }
}

private void traverseManagers(FragmentManager manager, SparseArray<FragmentManager> managers, int intent) {
    if (manager.getBackStackEntryCount() > 0) {
        managers.put(intent, manager);
    }
    if (manager.getFragments() == null) {
        return;
    }
    for (Fragment fragment : manager.getFragments()) {
        if (fragment != null) traverseManagers(fragment.getChildFragmentManager(), managers, intent + 1);
    }
}

答案 2 :(得分:2)

API 26 开始,FragmentTransaction中有一种setPrimaryNavigationFragment方法可用于

  

在此FragmentManager中将当前活动的片段设置为主要导航片段。

这意味着

  

如果未提供要弹出的ID或事务名称,则将首先调用主导航片段的子FragmentManager来处理委托的导航操作,例如FragmentManager.popBackStack()。片段系统外部的导航操作可以选择将这些操作委派给FragmentManager.getPrimaryNavigationFragment()返回的主要导航片段。

正如@la_urre在接受的答案中提到的那样,正如您在FragmentActivity的来源中所看到的那样,FragmentActivity的{​​{1}}将其onBackPressed称为FragmentManager会依次检查是否存在popBackStackImmediate()(我假设是主导航)片段,获取其子片段管理器并弹出其后栈。

答案 3 :(得分:-2)

@Override
public void onBackPressed() {
    FragmentManager fm = getSupportFragmentManager();
    if (fm.getBackStackEntryCount() > 0) {
        fm.popBackStack();
        return;
    }
    finish();
}