web-dev-qa-db-ja.com

ネストされたフラグメントとバックスタック

バックスタックは、Androidのネストされたフラグメントとの相互作用をサポートしていますか?

もしそうなら、私は何を間違っていますか?私の実装では、戻るボタンは、このトランザクションをバックスタックに追加したという事実を完全に無視しています。ネストされたフラグメントの問題が原因ではなく、私が何か間違ったことをしているだけだといいのですが。

次のコードは、私のフラグメントの1つに含まれており、新しいフラグメントを、現在表示されているネストされたフラグメントと交換するために使用されます。

     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();
18
MikeS

同じ問題があります。フラグメントをネストし、ネストされたフラグメントごとにバックスタックを保持したいと思います。

しかし...このケースはv4サポートライブラリでは処理されていないようです。ライブラリのFragmentActivityコードで、次のことがわかります。

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

MFragmentsはアクティビティのFragmentManagerを表しますが、このマネージャーがポップを子マネージャーに「伝播」しているようには見えません。回避策は、FragmentActivityから継承されたアクティビティで次のように、子マネージャーでpopBackStackImmediate()を手動で呼び出すことです。

private Fragment myFragmentContainer;

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

より良い方法とより自動化された方法があるかもしれませんが、私のニーズにはそれで大丈夫です。

30
la_urre

私の現在のプロジェクトでは、複数の「ネストされたレイヤー」があるため、トップレベルのフラグメントマネージャーに対してのみバックスタックを自動的にポップする次の回避策を考え出しました。

@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);
    }
}
4
MatrixDev

API 26の時点で、FragmentTransactionsetPrimaryNavigationFragment メソッドがあります。

このFragmentManagerで現在アクティブなフラグメントをプライマリナビゲーションフラグメントとして設定します。

この意味は

ポップ先のIDまたはトランザクション名が指定されていない場合、プライマリナビゲーションフラグメントの子FragmentManagerが最初に呼び出され、FragmentManager.popBackStack()などの委任されたナビゲーションアクションが処理されます。フラグメントシステム外のナビゲーション操作は、FragmentManager.getPrimaryNavigationFragment()によって返されるように、これらのアクションをプライマリナビゲーションフラグメントに委任することを選択できます。

受け入れられた回答で@la_urreが述べているように、またFragmentActivityのソースでわかるように、FragmentActivityonBackPressedはそのFragmentManagerpopBackStackImmediate()を呼び出します。次に、mPrimaryNav(プライマリナビゲーション、私は推測します)フラグメントがあるかどうかをチェックし、その子フラグメントマネージャーを取得して、バックスタックをポップします。

2
stan0