在底部标签导航

时间:2016-07-27 10:14:31

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

我正在开发具有以下UI结构的应用程序:

  • 一个Activity,名为 FoodActivity
    • Activity实施bottom navigation。因此,可以显示三类食物:水果
    • Activity有一个很大的Fragment容器,我在其中附加了水果Fragment当用户与底部标签交互时,
  • 每个外部Fragment fish 和鱼)都会在Fragments之间显示导航:它可以显示水果列表,以及所选水果的细节。
    • 因此,外部Fragments有另一个Fragment容器,我将Fragments附加到水果列表或水果详细信息中。

所以,它是一个主Activity,它有一个很大的Fragment容器,我交换Fragments,然后嵌套其他Fragments

App UI structure

要使用标签从一个外部Fragment切换到另一个外部{{从水果切换到),我在外部执行片段交易Fragment容器:

private void switchFragment(Fragment fragment, String fragmentTag) {
    final FragmentManager fm = getSupportFragmentManager();
    final FragmentTransaction ft = fm.beginTransaction();

    ft.replace(R.id.fragment_outer, fragment, fragmentTag);
    ft.commit();
}

问题是切换第一级Fragments时,ChildFragmentManager的状态未保留

例如,想象一下: - 我从 FuitFragment 开始 - FruitFragment 在创建时附加嵌套的 FruitListFragment - 用户在嵌套的Fragment容器中导航,从 FruitListFragment 导航到 FruitDetailFragment - 用户切换到另一个选项卡 - 用户切换回水果选项卡 - FuitFragment 的子FragmentManager *不会自动将 FruitDetailFragment 放入嵌套的片段容器中。

更具体地说,当切换回外部Fragment时:

    调用
  • onCreatesavedInstance == null
  • 调用
  • onCreateViewsavedInstance == null

因此,当调用外部Fragment onCreate方法时,我无法判断是否附加了子Fragment(通常与Activities一样) 。 此外,如果我不附加它(使用实例变量检查我是否切换回它),子Fragment容器将只是空的。

实验和笔记

  • 我已经尝试过,如果我在附加它时将外部片段事务添加到backstack,当切换回它时,onCreate方法不会被调用,而子FragmentManager将记住并且附上之前的片段。 但是,根据Google's specifications on bottom navigation,我无法将其添加到backstack。

  • setRetainInstace设置为true不会产生任何影响。

那么,我应该怎么做才能正确恢复孩子的状态FragmentManager

我做错了什么,或者说Android中嵌套片段的所有内容都没有得到很好的支持(或者有点破碎)而且我不应该使用嵌套片段提供导航?

2 个答案:

答案 0 :(得分:1)

正如阿巴斯指出的那样,问题在于我使用replace来切换片段。

我已经更改为放置外部片段的Activity中的代码,并且它可以工作:

private void showChildFragment(int itemId) {
    final FragmentManager fragmentManager = getSupportFragmentManager();
    final FragmentTransaction  transaction = fragmentManager.beginTransaction();

    final Fragment currentFragment = getSupportFragmentManager().findFragmentById(R.id.fragment_outer);
    if (currentFragment != null) {
        Log.v(TAG, "Detaching item #" + currentFragment);
        currentFragment.setMenuVisibility(false);
        currentFragment.setUserVisibleHint(false);
        transaction.detach(currentFragment);
    }

    // Do we already have this fragment?
    final String tag = makeFragmentTag(container.getId(), itemId);
    Fragment fragment = fragmentManager.findFragmentByTag(tag);
    if (fragment == null) {
        fragment = createFragmentForViewId(itemId);
        Log.v(TAG, "Adding item #" + itemId + ": f=" + fragment);
        transaction.add(container.getId(), fragment, tag);
    } else {
        Log.v(TAG, "Attaching item #" + itemId + ": f=" + fragment);
        transaction.attach(fragment);
    }
    fragment.setMenuVisibility(true);
    fragment.setUserVisibleHint(true);

    transaction.commitAllowingStateLoss();
    fragmentManager.executePendingTransactions();
}

private Fragment createFragmentForViewId(int itemId) {
    switch (itemId) {
        case FRAGMENT_ID_LIBRARY:
            return LibraryNavigationFragment.createInstance();
        case FRAGMENT_ID_FEED:
            return WebAppFragment.createInstance("feed");
        case FRAGMENT_ID_SUGGEST:
            return WebAppFragment.createInstance("suggest");
        default:
            throw new IllegalArgumentException();

    }
}

此代码几乎从android.support.v4.app.FragmentPagerAdapter复制粘贴为ViewPagers,使用Fragments工作,就像我想要的那样。

答案 1 :(得分:0)

使用getChildFragmentManager()不会崩溃。

private void switchFragment(Fragment fragment, String fragmentTag) {
    final FragmentManager fm = getChildFragmentManager();
    final FragmentTransaction ft = fm.beginTransaction();

    ft.replace(R.id.fragment_outer, fragment, fragmentTag);
    ft.commit();
}