Avec Android 4.2, la bibliothèque de support prend en charge les fragments imbriqués, voir ici . J'ai joué avec et trouvé un comportement / bogue intéressant concernant la pile arrière et getChildFragmentManager () . Lorsque vous utilisez getChildFragmentManager () et addToBackStack (nom de chaîne), en appuyant sur le bouton Précédent, le système ne descend pas de la pile arrière jusqu'au fragment précédent. D'un autre côté, lorsque vous utilisez getFragmentManager () et addToBackStack (String name), en appuyant sur le bouton Précédent, le système revient au fragment précédent.
Pour moi, ce comportement est inattendu. En appuyant sur le bouton de retour de mon appareil, je m'attends à ce que le dernier fragment ajouté à la pile arrière apparaisse, même si le fragment a été ajouté à la pile arrière dans le gestionnaire de fragments pour enfants.
Ce comportement est-il correct? Ce comportement est-il un bogue? Y a-t-il une solution à ce problème?
exemple de code avec getChildFragmentManager ():
public class FragmentceptionActivity extends FragmentActivity {
@Override
protected void onCreate(Bundle arg0) {
super.onCreate(arg0);
final FrameLayout wrapper1 = new FrameLayout(this);
wrapper1.setLayoutParams(new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT));
wrapper1.setId(1);
final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.WRAP_CONTENT);
params.topMargin = 0;
final TextView text = new TextView(this);
text.setLayoutParams(params);
text.setText("fragment 1");
wrapper1.addView(text);
setContentView(wrapper1);
getSupportFragmentManager().beginTransaction().addToBackStack(null)
.add(1, new Fragment1()).commit();
}
public class Fragment1 extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final FrameLayout wrapper2 = new FrameLayout(getActivity());
wrapper2.setLayoutParams(new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT));
wrapper2.setId(2);
final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.WRAP_CONTENT);
params.topMargin = 100;
final TextView text = new TextView(getActivity());
text.setLayoutParams(params);
text.setText("fragment 2");
wrapper2.addView(text);
return wrapper2;
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
getFragmentManager().beginTransaction().addToBackStack(null)
.add(2, new Fragment2()).commit();
}
}
public class Fragment2 extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final FrameLayout wrapper3 = new FrameLayout(getActivity());
wrapper3.setLayoutParams(new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT));
wrapper3.setId(3);
final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.WRAP_CONTENT);
params.topMargin = 200;
final TextView text = new TextView(getActivity());
text.setLayoutParams(params);
text.setText("fragment 3");
wrapper3.addView(text);
return wrapper3;
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
getChildFragmentManager().beginTransaction().addToBackStack(null)
.add(3, new Fragment3()).commit();
}
}
public class Fragment3 extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final FrameLayout wrapper4 = new FrameLayout(getActivity());
wrapper4.setLayoutParams(new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT));
wrapper4.setId(4);
final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.WRAP_CONTENT);
params.topMargin = 300;
final TextView text = new TextView(getActivity());
text.setLayoutParams(params);
text.setText("fragment 4");
wrapper4.addView(text);
return wrapper4;
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
getChildFragmentManager().beginTransaction().addToBackStack(null)
.add(4, new Fragment4()).commit();
}
}
public class Fragment4 extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final FrameLayout wrapper5 = new FrameLayout(getActivity());
wrapper5.setLayoutParams(new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT));
wrapper5.setId(5);
final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.WRAP_CONTENT);
params.topMargin = 400;
final TextView text = new TextView(getActivity());
text.setLayoutParams(params);
text.setText("fragment 5");
wrapper5.addView(text);
return wrapper5;
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
}
}
}
exemple de code avec getFragmentManager ():
public class FragmentceptionActivity extends FragmentActivity {
@Override
protected void onCreate(Bundle arg0) {
super.onCreate(arg0);
final FrameLayout wrapper1 = new FrameLayout(this);
wrapper1.setLayoutParams(new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT));
wrapper1.setId(1);
final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.WRAP_CONTENT);
params.topMargin = 0;
final TextView text = new TextView(this);
text.setLayoutParams(params);
text.setText("fragment 1");
wrapper1.addView(text);
setContentView(wrapper1);
getSupportFragmentManager().beginTransaction().addToBackStack(null)
.add(1, new Fragment1()).commit();
}
public class Fragment1 extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final FrameLayout wrapper2 = new FrameLayout(getActivity());
wrapper2.setLayoutParams(new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT));
wrapper2.setId(2);
final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.WRAP_CONTENT);
params.topMargin = 100;
final TextView text = new TextView(getActivity());
text.setLayoutParams(params);
text.setText("fragment 2");
wrapper2.addView(text);
return wrapper2;
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
getFragmentManager().beginTransaction().addToBackStack(null)
.add(2, new Fragment2()).commit();
}
}
public class Fragment2 extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final FrameLayout wrapper3 = new FrameLayout(getActivity());
wrapper3.setLayoutParams(new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT));
wrapper3.setId(3);
final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.WRAP_CONTENT);
params.topMargin = 200;
final TextView text = new TextView(getActivity());
text.setLayoutParams(params);
text.setText("fragment 3");
wrapper3.addView(text);
return wrapper3;
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
getFragmentManager().beginTransaction().addToBackStack(null)
.add(3, new Fragment3()).commit();
}
}
public class Fragment3 extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final FrameLayout wrapper4 = new FrameLayout(getActivity());
wrapper4.setLayoutParams(new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT));
wrapper4.setId(4);
final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.WRAP_CONTENT);
params.topMargin = 300;
final TextView text = new TextView(getActivity());
text.setLayoutParams(params);
text.setText("fragment 4");
wrapper4.addView(text);
return wrapper4;
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
getFragmentManager().beginTransaction().addToBackStack(null)
.add(4, new Fragment4()).commit();
}
}
public class Fragment4 extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final FrameLayout wrapper5 = new FrameLayout(getActivity());
wrapper5.setLayoutParams(new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT));
wrapper5.setId(5);
final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.WRAP_CONTENT);
params.topMargin = 400;
final TextView text = new TextView(getActivity());
text.setLayoutParams(params);
text.setText("fragment 5");
wrapper5.addView(text);
return wrapper5;
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
}
}
}
Réponses:
Cette solution peut être une meilleure version de @Sean answer:
Encore une fois, j'ai préparé cette solution basée sur la réponse @Sean ci-dessus.
Comme @ AZ13 l'a dit, cette solution n'est réalisable que dans des situations de fragments enfants à un niveau. Dans le cas des fragments à plusieurs niveaux, les travaux deviennent un peu complexes, je recommande donc d'essayer cette solution uniquement dans le cas réalisable que j'ai dit. =)
Remarque: Comme
getFragments
méthode est maintenant une méthode privée, cette solution ne fonctionnera pas. Vous pouvez consulter les commentaires pour un lien qui suggère une solution à cette situation.la source
getFragments
est maintenant public.Cela ressemble à un bug. Jetez un œil à: http://code.google.com/p/android/issues/detail?id=40323
Pour une solution de contournement que j'ai utilisée avec succès (comme suggéré dans les commentaires):
la source
La vraie réponse à cette question se trouve dans la fonction de la transaction de fragment appelée setPrimaryNavigationFragment.
Vous devez définir cette fonction sur le fragment parent initial lorsque l'activité l'ajoute. J'ai une fonction replaceFragment dans mon activité qui ressemble à ceci:
Cela vous donne le même comportement que si vous reveniez du Fragment B normal au Fragment A, sauf que maintenant c'est aussi sur les fragments enfants!
la source
Cette solution peut être une meilleure version de la réponse @ismailarilik:
Version du fragment imbriqué
la source
SupportFragmentManager
et à la place uniquement avec le StandardFragmentManager
?Avec cette réponse, il gérera la vérification arrière récursive et donnera à chaque fragment la possibilité de remplacer le comportement par défaut. Cela signifie que vous pouvez demander à un fragment qui héberge un ViewPager de faire quelque chose de spécial, comme faire défiler jusqu'à la page qui en tant que back-stack, ou faire défiler jusqu'à la page d'accueil, puis au retour suivant, appuyez sur Quitter.
Ajoutez ceci à votre activité qui étend AppCompatActivity.
Ajoutez ceci à votre BaseFragment ou à la classe dont vous pouvez hériter de tous vos fragments.
la source
Ce code naviguera dans l'arborescence des gestionnaires de fragments et retournera le dernier qui a été ajouté qui contient tous les fragments qu'il peut sortir de la pile:
Appelez la méthode:
la source
La raison en est que votre activité dérive de FragmentActivity, qui gère la pression de la touche RETOUR (voir la ligne 173 de FragmentActivity .
Dans notre application, j'utilise un ViewPager (avec des fragments) et chaque fragment peut avoir des fragments imbriqués. La façon dont j'ai géré cela est de:
void onBackKeyPressed()
Notez également que j'utilise
getChildFragmentManager()
dans les fragments pour imbriquer correctement les fragments. Vous pouvez voir une discussion et une explication dans cet article des développeurs Android .la source
si vous utilisez un fragment dans un fragment, utilisez
getChildFragmentManager()
si vous utilisez un fragment enfant et le remplacez, utilisez
getParentFragmentManager()
si les deux ne fonctionnent pas pour vous, essayez ceci
getActivity().getSupportFragmentManager()
la source
J'ai pu gérer la pile arrière de fragment en ajoutant au fragment parent cette méthode à la méthode onCreate View () et en passant la vue racine.
La méthode isEnableFragmentBackStack () est un drapeau booléen pour savoir quand je suis sur le fragment principal ou sur le suivant.
Assurez-vous que lorsque vous validez le fragment qui doit avoir une pile, vous devez ajouter la méthode addToBackstack.
la source
Cette solution peut être meilleure, car elle vérifie tous les niveaux de fragments imbriqués:
dans votre activité,
onBackPressed
vous pouvez simplement l'appeler ainsi:la source
Merci à tous pour leur aide, cette (version peaufinée) fonctionne pour moi:
REMARQUE: vous souhaiterez probablement également définir la couleur d'arrière-plan de ces fragments imbriqués sur la couleur d'arrière-plan de la fenêtre du thème de l'application, car par défaut, ils sont transparents. Un peu en dehors de la portée de cette question, mais cela est accompli en résolvant l'attribut android.R.attr.windowBackground et en définissant l'arrière-plan de la vue Fragment sur cet ID de ressource.
la source
Plus de 5 ans et cette question est toujours d'actualité. Si vous ne souhaitez pas utiliser fragmentManager.getFragments () en raison de sa restriction. Étendez et utilisez les classes ci-dessous:
NestedFragmentActivity.java
NestedFragment.java
Explication:
Chaque activité et fragment issu des classes ci-dessus gère leur propre back stack pour chacun de leurs enfants, et les enfants des enfants, etc. La backstack est simplement un enregistrement de balises / identifiants de "fragment actif". La mise en garde est donc de toujours fournir une balise et / ou un identifiant pour votre fragment.
Lors de l'ajout à la backstack dans un childFragmentManager, vous devrez également appeler "addToParentBackStack ()". Cela garantit que le tag / id du fragment est ajouté dans le fragment / activité parent pour les pops ultérieurs.
Exemple:
la source
Je l'ai implémenté correctement si personne n'a trouvé de réponse jusqu'à présent
ajoutez simplement cette méthode sur votre fragment imbriqué enfant
la source
J'ai résolu ce problème en conservant le fragment actuellement ouvert dans la propriété de l'activité. Ensuite, je remplace la méthode
C'est ainsi que j'ajoute un fragment enfant dans un fragment actuellement ouvert à partir de lui-même.
Il s'agit de la mise en page xml du fragment parent et du fragment ajouté
la source
Après avoir observé certaines solutions présentées ici, j'ai trouvé que pour permettre la flexibilité et le contrôle du fragment parent quant au moment où la pile de sauts ou lorsque l'action de retour doit être ignorée, j'utilise plutôt une telle implémentation:
Définition d'une interface "ParentFragment":
}
Remplacer "onBackPressed" dans l'activité parent (ou dans BaseActivity):
Et puis autorisez le fragment parent à gérer comme il le souhaite, par exemple:
Cela permet d'éviter de penser qu'il y a un fragment enfant légitime à supprimer lors de l'utilisation d'un pager de vue par exemple (et le nombre d'entrées de back stack> 0).
la source
Si vous avez un
DialogFragment
qui à son tour a des fragments imbriqués, la «solution de contournement» est un peu différente. Au lieu de définir unonKeyListener
sur lerootView
, vous devrez le faire avec leDialog
. Vous allez également mettre en place unDialogInterface.OnKeyListener
et nonView
un. Bien sûr, souvenez-vousaddToBackStack
!Voici ce que vous devez faire dans le onCreateDialog
la source
Dialog
(nonDialogFragment
) l'écouteur et l'écouteur que vous utilisez estDialogInterface.OnKeyListener
- le code fonctionne et est complet (et en cours d'utilisation). Pourquoi ne donnez-vous pas votre situation et peut-être que je peux vous aider.pour ChildFragments cela fonctionne.
la source