Le fragment n'est pas remplacé mais placé au-dessus du précédent

104

Activité:

FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();

Fragment1 fragment = new Fragment1();
Fragment2 fragment2 = new Fragment2();

transaction.replace(R.id.Fragment1, fragment);
transaction.addToBackStack(null);
transaction.commit();

FragmentTransaction transaction2 = getSupportFragmentManager().beginTransaction();
transaction2.replace(R.id.Fragment1, fragment2);
transaction2.addToBackStack(null);
transaction2.commit();

Code dans la vue:

<fragment
    android:id="@+id/Fragment1"
    android:name="com.landa.fragment.Fragment1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentBottom="true"
    android:layout_alignParentLeft="true"
    android:layout_below="@+id/include1" /> 

Le problème est que le contenu n'est pas vraiment remplacé - il est placé au-dessus (donc il se chevauche).

Lorsque je clique en arrière, le premier fragment s'affiche correctement (sans le second), mais initialement les deux sont visibles (je veux que seul le dernier soit visible).

Qu'est-ce que j'oublie ici?

Outil
la source
Dans mon cas, le problème était dû au fait que je n'utilisais pas l'identifiant approprié de la vue du conteneur, c'est-à-dire que je ne passais pas le bon containerViewId(dans la replaceméthode).
nbro

Réponses:

145

Vous faites deux choses mal ici:

  1. Vous ne pouvez pas remplacer un fragment placé de manière statique dans un xmlfichier de modèle. Vous devez créer un conteneur (par exemple a FrameLayout) dans la mise en page, puis ajouter le fragment par programme en utilisant FragmentTransaction.

  2. FragmentTransaction.replaceattend l'ID du conteneur qui contient le fragment et non l'ID du fragment comme premier paramètre. Vous devez donc passer le premier argument en tant qu'ID du conteneur auquel vous avez ajouté le premier fragment.

Vous pouvez vous référer à ce lien pour plus de détails.

Sapan Diwakar
la source
17
Il FrameLayoutvaut mieux utiliser comme conteneur que d’utiliser LinearLayout.
Marcel Bro
3
L'utilisation d'un FrameLayout vide dans Activity a également résolu mon problème
Subtle Fox
1
Cela fonctionne en faisant cela. Mais alors, lorsque je lance mon application et que j'appuie immédiatement sur le bouton retour, je me retrouve dans un état où le fragment est vide, au lieu de quitter l'application?
MasterScrat
@MasterScrat Omettez le addTobackStack(..)lorsque vous effectuez votre transaction pour la première fois. Cela évitera de placer le conteneur FrameLayout vide sur la pile arrière. Vous pourrez toujours revenir au fragment que vous ajoutez.
Alex Meuer
Voici une superbe vidéo qui montre votre explication. youtube.com/watch?v=EbcdMxAIr54
Apprenant SQL et Java
32

J'ai eu un problème similaire, mais mon problème était que j'utilisais deux gestionnaires de fragments différents: un de getSupportFragmentManager()et un de getFragmentManager(). Si j'ajoutais un fragment avec SupportFragmentManageret que j'essayais de remplacer le fragment par FragmentManager, le fragment serait simplement ajouté par-dessus. J'avais besoin de changer le code pour que le même FragmentManagersoit utilisé et cela a réglé le problème.

swbandit
la source
17

Le site des développeurs Android suggère l'utilisation d'un FrameLayoutpour charger des fragments de manière dynamique au moment de l'exécution. Vous avez codé en dur le fragment dans votre fichier xml. Il ne peut donc pas être supprimé au moment de l'exécution comme mentionné dans ce lien:

http://developer.android.com/training/basics/fragments/creating.html

ce lien montre comment ajouter des fragments via votre programme:

http://developer.android.com/training/basics/fragments/fragment-ui.html

Anthony Poonam
la source
7

J'ai eu le même problème et j'ai vu toutes les réponses, mais aucune d'elles ne contenait mon erreur! Avant d'essayer de remplacer le fragment actuel, je montrais le fragment par défaut dans le xml de l'activité du conteneur comme ceci:

<FrameLayout
    android:id="@+id/fragment_frame_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <fragment
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:name="....ShopFragment"
        android:id="@+id/fragment"
        tools:layout="@layout/fragment_shop" />
</FrameLayout>

après cela, même si je passais le FrameLayoutà la fragmentTransaction.replace()mais j'ai eu le problème exact. il montrait le deuxième fragment au-dessus du précédent.

Le problème résolu en supprimant le fragment du xml et en l'affichant par programme dans la onCreate()méthode de l'activité du conteneur pour l'aperçu par défaut au démarrage du programme comme ceci:

    fragmentTransaction = getFragmentManager().beginTransaction();
    fragmentTransaction.replace(R.id.fragment_frame_layout,new ShopFragment());
    fragmentTransaction.addToBackStack(null);
    fragmentTransaction.commit();

et l'activité du conteneur xml:

<FrameLayout
    android:id="@+id/fragment_frame_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
Emad
la source
4

Vous pouvez effacer backStack avant de remplacer les fragments:

    FragmentManager fm = getActivity().getSupportFragmentManager();

    for (int i = 0; i < fm.getBackStackEntryCount(); i++) {
        fm.popBackStack();
    }

    // replace your fragments
Michał Z.
la source
le problème est qu'il a déclaré le fragment dans son fichier de mise en page xml. Par conséquent, il ne peut pas être supprimé / remplacé au moment de l'exécution.
Poonam Anthony
cela a fonctionné pour moi, essayer de remplacer un fragment sans effacer la backstack semblait laisser l'entrée de backstack la plus récente au-dessus de tout autre fragment.
speedynomads
3
<FrameLayout
    android:id="@+id/fragment_frame_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="?android:windowBackground">
//Add fragment here
</FrameLayout>

Ajoutez android:background="?android:windowBackground">au conteneur dans lequel réside votre fragment. Dans mon cas, j'ai ajouté un FrameLayout, cela devrait aider.

Ralph Tashinga Nyoni
la source
1

Utilisez un conteneur au lieu d'utiliser un fragment

<FrameLayout
        android:id="@+id/container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="Hello World!" />

Maintenant dans MainActivity

if(condition)
    getFragmentManager().beginTransaction().replace(R.id.container,new FirstFragment()).commit();                    
else
    getFragmentManager().beginTransaction().replace(R.id.container, new SecondFragment()).commit();

Veuillez noter que votre classe de fragment doit importer "android.app.Fragment". Assurez-vous que vous utilisez "support.v4" ou les implémentations "originales" et ne les mélangez pas. J'avais ce problème parce que je les avais mélangés.

Vikash Kumar Verma
la source
0

Je suis d'accord avec la réponse de Sapan Diwakar. Mais j'ai trouvé une solution de contournement sur la façon de procéder.

Tout d'abord, dans votre activité (par exemple activity_main), où vous avez toutes les mises en page, ajoutez un fichier FrameLayout. Sa hauteur et sa largeur devraient être match parent. Aussi, donnez-lui un id.

Maintenant, dans votre fragment qui va remplacer la mise en page actuelle, appelez onPause()et onResume(). Initialisez tous les conteneurs internes dans View. Et mettez-les visibilityà l' GONEintérieuronResume() et à l' VISIBLEintérieuronPause() .

REMARQUE : pas celui FrameLayoutque vous remplacez par ce fragment.

Supposons que vous ayez ViewPager, TabLayout, ImageViewet une coutume <fragment>dans activity_main.xml. Ajoutez, FrameLayoutcomme mentionné ci-dessus.

Dans abcFragment.java, en onClick()fonction, ajouter addToBackstack(null)à transaction.

Exemple de code:

dans xyzFragment, qui va remplacer abcFragment (et tout ce qui est affiché dans activity_main.xml), faites ceci

@Override
    public void onResume() {
        super.onResume();

    // On resume, make everything in activity_main invisible except this fragment.
    slidingTabs = getActivity().findViewById(R.id.sliding_tabs);
    viewPager = getActivity().findViewById(R.id.pager);
    miniPlayerFragment = getActivity().findViewById(R.id.mini_pager);

    slidingTabs.setVisibility(View.GONE);
    viewPager.setVisibility(View.GONE);
    miniPlayerFragment.setVisibility(View.GONE);
}

@Override
public void onPause() {
    super.onPause();

    // Make everything visible again
    slidingTabs = getActivity().findViewById(R.id.sliding_tabs);
    viewPager = getActivity().findViewById(R.id.pager);
    miniPlayerFragment = getActivity().findViewById(R.id.mini_pager);

    slidingTabs.setVisibility(View.VISIBLE);
    viewPager.setVisibility(View.VISIBLE);
    miniPlayerFragment.setVisibility(View.VISIBLE);
}

Bon codage!

TheOnlyAnil
la source
0

Vous pouvez utiliser la méthode setTransition de FragmentTransaction pour résoudre le problème de chevauchement.

transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
Lavakush
la source
0

Dans Oncreate ()

  BaseFragmentloginpage fragment = new BaseFragmentloginpage();
            android.support.v4.app.FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
            fragmentTransaction.replace(R.id.frame, fragment);
            fragmentTransaction.isAddToBackStackAllowed();
            fragmentTransaction.commit();

maintenant, ce sera toujours votre fragment par défaut ... si vous ajoutez un fragment dans une mise en page XML, il se chevauchera toujours, alors définissez le contenu initial avec le fragment au moment de l'exécution

Volverine
la source
0

J'ai eu le même problème après avoir utilisé ce problème résolu

  1. Prenez la disposition du cadre où vous remplacez votre fragment

    <FrameLayout
                    android:id="@+id/fragment_place"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent" />
  2. et code de remplacement

    public void selectFrag(View view) {
    Fragment fr;
    
      if(view == findViewById(R.id.button2))
    {
         fr = new FragmentTwo();
    
     }else {
         fr = new FragmentOne();
     }
     FragmentManager fm = getFragmentManager();
     FragmentTransaction fragmentTransaction = fm.beginTransaction();
     fragmentTransaction.replace(R.id.fragment_place, fr);
     fragmentTransaction.commit();

si vous voulez un exemple complet, je vous enverrai juste un commentaire moi ......

Sunil
la source
0

J'ai également eu le même problème, mais c'est parce que je n'avais pas changé la couleur de fond du fragment que j'essayais d'ajouter à ma mise en page.

Essayez de faire ceci, avec layout_heightet layout_widthréglez surmatch_parent

Swastik Udupa
la source
0

Une fois, j'ai eu ce problème et j'ai découvert que c'était parce que j'avais accidentellement supprimé l' android:backgroundattribut manquant dans votre code xml. Je pense que cela fonctionne comme lorsque vous peignez un mur, android:backgroundc'est la couleur du mur et les autres vues sont placées au-dessus de cette couleur de base. Lorsque vous ne peignez pas le mur avant de positionner vos vues, elles seront au-dessus de ce qui était déjà dans ce mur, dans votre cas, votre autre fragment. Je ne sais pas si cela vous aidera, bonne chance.

Miguel Pinheiro
la source
0

J'ai essayé avant tout le cas et essayé de résoudre le problème mais je n'ai toujours pas trouvé de solution. Je ne sais pas pourquoi ça ne marche pas pour moi. Je suis d'accord avec les réponses ci-dessus car beaucoup sont d'accord avec cela.

Je ne fais qu'étendre la réponse et voici la manière qui fonctionne pour moi.

J'ai ajouté cette propriété android:clickable="true"dans la mise en page parent supérieure du fragment.xmlfichier.

J'espère que quelqu'un obtiendra de l'aide.

Shailesh
la source
0

Merci à Sapan Diwakar et aux autres. Cette réponse m'a aidé. J'ai simplement créé un RelativeLayout sans fragment à l'intérieur, utilisé le RelativeLayout comme vue parent ou de groupe, spécifié cette vue de groupe dans la transaction à remplacer, et cela a fonctionné.

Code:

getSupportFragmentManager().beginTransaction()
                            .replace(R.id.content_group_view, itemDetailFragment).commit();

XML:

 <RelativeLayout
         android:id="@+id/content_group_view"
         android:layout_width="match_parent"
         android:layout_height="match_parent">

 </RelativeLayout>
Craig D
la source
0

Vérifiez votre ID de disposition de cadre et remplacez-le comme ci-dessous

fragmentTransactionChange = MainActivity.this.getSupportFragmentManager().beginTransaction();
fragmentTransactionChange.replace(R.id.progileframe, changeFragment);
fragmentTransactionChange.addToBackStack(null);
fragmentTransactionChange.commit();
Sandeep Pareek
la source