158 votes

Fragment Inside Fragment

J'ai besoin d'aide pour travailler sur un fragment à l'intérieur d'un fragment. Je suis confronté à un problème lorsque j'appuie sur le bouton retour. L'écran principal de l'application a des boutons et en appuyant sur chaque bouton, la vue est remplacée par un nouveau fragment. fragment (et ce fragment contient un autre fragment), L'ajout/le remplacement dynamique de fragments fonctionne bien. bouton1 le fragment a été remplacé, la même chose se produit en appuyant sur le bouton, mais si Mais si j'appuie à nouveau sur le bouton, je reçois une exception :

"Duplicate id 0x7f05000a, tag null, or parent id 0x7f050009 with
another fragment for com........ fragmentname"

signifie que le fragment ou les fragments internes sont déjà ajoutés et que j'essaie d'ajouter à nouveau, quelqu'un a une idée de la façon de travailler avec des fragment et le déplacement en avant et en arrière sans aucun problème, merci pour la support.

MainActivity, où les fragments sont ajoutés de manière dynamique et les remplacés.

public class FragmentInsideFragmentTestActivity extends Activity {

    private Button button1;
    private Button button2;
    private Button button3;
    private Button button4;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        button1 =(Button) this.findViewById(R.id.button1);
        button1.setOnClickListener(new View.OnClickListener() {
           public void onClick(View view) {
               onButtonClick(view);
            }
        });

        button2 =(Button) this.findViewById(R.id.button2);
        button2.setOnClickListener(new View.OnClickListener() {
            public void onClick(View view) {
                onButtonClick(view);
            }
        });

        button3 =(Button) this.findViewById(R.id.button3);
        button3.setOnClickListener(new View.OnClickListener() {
            public void onClick(View view) {
               onButtonClick(view);
            }
        });

        button4 =(Button) this.findViewById(R.id.button4);
        button4.setOnClickListener(new View.OnClickListener() {
           public void onClick(View view) {
               onButtonClick(view);
           }
        });
    }

    public void onButtonClick(View v) {
        Fragment fg;

        switch (v.getId()) {
           case R.id.button1:
                   fg=FirstFragment.newInstance();
                   replaceFragment(fg);
                   break;
           case R.id.button2:
                   fg=SecondFragment.newInstance();
                   replaceFragment(fg);
                   break;
           case R.id.button3:
                   fg=FirstFragment.newInstance();
                   replaceFragment(fg);
                   break;
           case R.id.button4:
                   fg=SecondFragment.newInstance();
                   replaceFragment(fg);
                   break;
        }
    }

    private void replaceFragment(Fragment newFragment) {
       FragmentTransaction trasection = getFragmentManager().beginTransaction();

        if(!newFragment.isAdded()) {
            try {
                //FragmentTransaction trasection =
                getFragmentManager().beginTransaction();
                trasection.replace(R.id.linearLayout2, newFragment);
                trasection.addToBackStack(null);
                trasection.commit();
            } catch (Exception e) {
                // TODO: handle exception
                // AppConstants.printLog(e.getMessage());
            } else {
                trasection.show(newFragment);
            }
        }
    }

Voici la mise en page : main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical">

    <LinearLayout
        android:id="@+id/linearLayout1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <Button
            android:id="@+id/button1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Button1" />

        <Button
            android:id="@+id/button2"
            android:text="Button2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />

        <Button
            android:id="@+id/button3"
            android:text="Button3"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />

        <Button
            android:id="@+id/button4"
            android:text="Button4"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
    </LinearLayout>

    <LinearLayout
        android:id="@+id/linearLayout2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal" />
</LinearLayout>

J'espère avoir essayé de clarifier mon problème.

1 votes

Le code ci-dessus fonctionne parfaitement bien pour moi avec Android 3.1

3 votes

Duplicata possible de Fragments dans les fragments

0 votes

Pour plus de détails, voir stackoverflow.com/a/11020531/1219456

297voto

CommonsWare Points 402670

À ma connaissance, les fragments ne peuvent pas contenir d'autres fragments.


UPDATE

Avec les versions actuelles du paquet de support Android -- ou les fragments natifs sur le niveau 17 de l'API et plus -- vous pouvez imbriquer des fragments, au moyen des éléments suivants getChildFragmentManager() . Notez que cela signifie que vous devez utiliser la version de fragments du package de support Android sur les niveaux 11-16 de l'API, car même s'il existe une version native de fragments sur ces appareils, cette version ne dispose pas de getChildFragmentManager() .

34 votes

La plateforme est vraiment nulle ici. J'ai passé trois heures à déboguer ça parce que le fragment interne s'affichait bien la première fois, mais disparaître après un changement d'orientation de l'écran. Pas d'exception, d'info journal, rien. En passant à getChildFragmentManager() et la suppression setRetainInstance(true) du fragment intérieur (pitié) l'a fixé. Merci de m'avoir encore sauvé la mise, @CommonsWare.

73voto

Nik Points 1937

Depuis Android 4.2 (API 17), les fragments imbriqués sont disponibles. http://developer.Android.com/about/versions/Android-4.2.html#NestedFragments

Pour placer un fragment à l'intérieur d'un autre fragment, utilisez getChildFragmentManager().

Il est également disponible dans la bibliothèque de soutien !

0 votes

Veuillez mettre à jour votre réponse pour mentionner que la bibliothèque de support supporte déjà les fragements imbriqués à partir d'Android 1.6+.

13voto

Napolean Points 383

Les fragments peuvent être ajoutés à l'intérieur d'autres fragments, mais vous devrez alors les retirer du fragment parent à chaque fois que vous en aurez besoin. onDestroyView() du fragment parent est appelée. Et encore une fois, ajoutez-le dans la méthode du fragment parent onCreateView() méthode.

Fais comme ça :

@Override
    public void onDestroyView()
    {
                FragmentManager mFragmentMgr= getFragmentManager();
        FragmentTransaction mTransaction = mFragmentMgr.beginTransaction();
                Fragment childFragment =mFragmentMgr.findFragmentByTag("qa_fragment")
        mTransaction.remove(childFragment);
        mTransaction.commit();
        super.onDestroyView();
    }

5 votes

Cela n'a pas fonctionné pour moi. J'avais un fragment qui gonflait une vue contenant deux vues enfants. Dans onActivityCreated() il a ajouté deux fragments, un dans chacune des vues, en utilisant getFragmentManager() . Cela a fonctionné la première fois, mais lors de la rotation et de la reprise, seul un des fragments était visible. Le comportement était correct avec getChildFragmentManager() à la place. L'approche suggérée ici a jeté une exception puisque l'activité onSaveInstanceState() avait déjà été appelé. Valider la transaction en utilisant commitAllowingStateLoss() a évité l'exception mais n'a pas résolu le problème initial.

0 votes

9voto

Vetalll Points 586

J'ai résolu ce problème. Vous pouvez utiliser la bibliothèque Support et ViewPager . Si vous n'avez pas besoin du balayage par geste, vous pouvez désactiver le balayage. Voici donc un peu de code pour améliorer ma solution :

public class TestFragment extends Fragment{
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View v = inflater.inflate(R.layout.frag, container, false);
    final ArrayList<Fragment> list = new ArrayList<Fragment>();

    list.add(new TrFrag());
    list.add(new TrFrag());
    list.add(new TrFrag());

    ViewPager pager = (ViewPager) v.findViewById(R.id.pager);
    pager.setAdapter(new FragmentPagerAdapter(getChildFragmentManager()) {
        @Override
        public Fragment getItem(int i) {
            return list.get(i);
        }

        @Override
        public int getCount() {
            return list.size();
        }
    });
    return v;
}
}

P.S.C'est un code laid pour le test, mais il améliore que c'est possible.

P.P.S Fragment intérieur ChildFragmentManager doit être transmis à ViewPagerAdapter

3voto

LoveBigPizza Points 21

Vous pouvez ajouter FrameLayout au fragment et le remplacer par un autre fragment lors de son initialisation.

De cette façon, vous pouvez considérer l'autre fragment comme étant à l'intérieur du premier fragment.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X