Das Fragment wird nicht ersetzt, sondern über das vorherige gelegt


104

Aktivität:

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 in der Ansicht:

<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" /> 

Das Problem ist, dass der Inhalt nicht wirklich ersetzt wird - er wird oben platziert (so dass er sich überlappt).

Wenn ich zurückklicke, wird das erste Fragment richtig angezeigt (ohne das zweite), aber anfangs sind beide sichtbar (ich möchte, dass nur das letzte sichtbar ist).

Was fehlt mir hier?


In meinem Fall lag das Problem daran, dass ich nicht die entsprechende ID der Containeransicht verwendet habe, dh ich habe nicht die richtige ID containerViewId(in der replaceMethode) übergeben.
nbro

Antworten:


145

Sie machen hier zwei Dinge falsch:

  1. Sie können ein Fragment nicht ersetzen, das statisch in einer xmlLayoutdatei platziert ist. Sie sollten einen Container (z. B. a FrameLayout) im Layout erstellen und das Fragment dann programmgesteuert mit hinzufügen FragmentTransaction.

  2. FragmentTransaction.replaceerwartet die ID des Containers, der das Fragment enthält, und nicht die ID des Fragments als ersten Parameter. Sie sollten also das erste Argument als ID des Containers übergeben, dem Sie das erste Fragment hinzugefügt haben.

Weitere Informationen finden Sie unter diesem Link .


17
Die Verwendung FrameLayoutals Container ist besser als die Verwendung LinearLayout.
Marcel Bro

3
Die Verwendung eines leeren FrameLayout in Aktivität löste auch mein Problem
Subtle Fox

1
Es funktioniert dabei. Aber wenn ich dann meine Anwendung starte und sofort die Zurück-Taste drücke, bin ich in einem Zustand, in dem das Fragment leer ist, anstatt die App zu beenden?
MasterScrat

@MasterScrat Lassen Sie das aus, addTobackStack(..)wenn Sie Ihre Transaktion zum ersten Mal ausführen . Dadurch wird vermieden, dass der leere FrameLayout-Container auf den hinteren Stapel gelegt wird. Sie können weiterhin zu dem Fragment navigieren, das Sie hinzugefügt haben.
Alex Meuer

Hier ist ein großartiges Video, das Ihre Erklärung demonstriert. youtube.com/watch?v=EbcdMxAIr54
SQL- und Java-Lerner

32

Ich hatte ein ähnliches Problem, aber mein Problem war, dass ich zwei verschiedene Fragmentmanager verwendete: einen von getSupportFragmentManager()und einen von getFragmentManager(). Wenn ich ein Fragment mit dem hinzufügen SupportFragmentManagerund dann versuchen würde, das Fragment durch das zu ersetzen FragmentManager, würde das Fragment nur oben hinzugefügt. Ich musste den Code ändern, damit derselbe FragmentManagerverwendet wurde und das Problem behoben war.



7

Ich hatte das gleiche Problem und sah alle Antworten, aber keine enthielt meinen Fehler! Bevor ich versuchte, das aktuelle Fragment zu ersetzen, zeigte ich das Standardfragment in der XML-Datei der Containeraktivität wie folgt an:

<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>

danach habe ich zwar das FrameLayoutan das weitergegeben fragmentTransaction.replace()aber ich hatte das genaue problem. es zeigte das zweite Fragment über dem vorherigen.

Das Problem wurde behoben, indem das Fragment aus der XML entfernt und programmgesteuert in der onCreate()Methode der Containeraktivität für die Standardvorschau beim Start des Programms wie folgt angezeigt wurde:

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

und die Containeraktivität xml:

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

4

Sie können backStack löschen, bevor Sie Fragmente ersetzen:

    FragmentManager fm = getActivity().getSupportFragmentManager();

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

    // replace your fragments

Das Problem ist, dass er das Fragment in seiner XML-Layoutdatei deklariert hat. Daher kann es zur Laufzeit nicht entfernt / ersetzt werden.
Poonam Anthony

Dies funktionierte für mich. Der Versuch, ein Fragment zu ersetzen, ohne den Backstack zu löschen, schien den neuesten Backstack-Eintrag über jedem anderen Fragment zu belassen.
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>

Fügen Sie android:background="?android:windowBackground">dem Container hinzu, in dem sich Ihr Fragment befindet. In meinem Fall habe ich ein hinzugefügt FrameLayout, das sollte helfen.


1

Verwenden Sie einen Container anstelle eines Fragments

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

Jetzt in MainActivity

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

Bitte beachten Sie, dass Ihre Fragmentklasse 'android.app.Fragment' importieren sollte. Stellen Sie sicher, dass Sie "support.v4" oder die "ursprünglichen" Implementierungen verwenden und diese nicht mischen. Ich bekam dieses Problem, weil ich sie gemischt hatte.


0

Ich stimme der Antwort von Sapan Diwakar zu. Aber ich habe eine Problemumgehung gefunden, wie das geht.

activity_mainFügen Sie in Ihrer Aktivität (z. B. ), in der Sie alle Layouts haben, zunächst a hinzu FrameLayout. Es sollte Höhe und Breite sein match parent. Geben Sie es auch ein id.

Rufen Sie nun in Ihrem Fragment, das das aktuelle Layout ersetzen soll, onPause()und auf onResume(). Initialisieren Sie alle inneren Container in View. Und setzen visibilitysie GONEeinonResume() und VISIBLEeinonPause() .

HINWEIS : Nicht das, FrameLayoutwas Sie durch dieses Fragment ersetzen.

Angenommen , Sie haben ViewPager, TabLayout, ImageViewund ein Brauch <fragment>in activity_main.xml. Fügen Sie ein FrameLayoutwie oben erwähnt hinzu.

In abcFragment.java, in onClick()Funktion, fügen Sie addToBackstack(null)in transaction.

Beispielcode:

Führen Sie dies in xyzFragment aus, das abcFragment (und alles, was in activity_main.xml angezeigt wird) ersetzen wird

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

Viel Spaß beim Codieren!


0

Sie können die setTransition-Methode von FragmentTransaction verwenden, um überlappende Probleme zu beheben.

transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);

0

In Oncreate ()

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

Jetzt ist dies immer Ihr Standardfragment. Wenn Sie ein Fragment im XML-Layout hinzufügen, überlappt es sich immer. Legen Sie daher zur Laufzeit den anfänglichen Inhalt mit dem Fragment fest


0

Ich hatte das gleiche Problem, nachdem ich dieses Problem gelöst hatte

  1. Nehmen Sie das Rahmenlayout, in dem Sie Ihr Fragment ersetzen

    <FrameLayout
                    android:id="@+id/fragment_place"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent" />
  2. und Code für den Austausch

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

Wenn du ein ganzes Beispiel willst, sende ich dir einfach einen Kommentar ......


0

Ich hatte auch das gleiche Problem, aber es war, weil ich die Hintergrundfarbe des Fragments, das ich zu meinem Framelayout hinzufügen wollte, nicht geändert hatte.

Versuchen Sie dies mit layout_heightund layout_widthsetzen Sie aufmatch_parent


0

Ich hatte einmal dieses Problem und fand heraus, dass es daran lag, dass ich versehentlich das android:backgroundAttribut gelöscht hatte, das in Ihrem XML-Code fehlt. Ich glaube, es funktioniert so, als ob Sie eine Wand streichen. Es android:backgroundist die Farbe, die die Wand haben wird, und die anderen Ansichten werden über dieser Grundfarbe platziert. Wenn Sie die Wand vor dem Positionieren Ihrer Ansichten nicht streichen, befinden sie sich auf dem, was sich bereits in dieser Wand befand, in Ihrem Fall auf Ihrem anderen Fragment. Ich weiß nicht, ob dir das helfen wird, viel Glück.


0

Ich habe vor allem den Fall versucht und versucht, das Problem zu beheben, aber immer noch keine Lösung gefunden. Ich weiß nicht, warum es bei mir nicht funktioniert. Ich stimme den obigen Antworten zu, weil so viele damit einverstanden sind.

Ich erweitere nur die Antwort und unten ist die Art und Weise, wie es für mich funktioniert.

Ich habe diese Eigenschaft android:clickable="true"im obersten übergeordneten Layout der fragment.xmlDatei hinzugefügt .

Ich hoffe jemand bekommt Hilfe.


0

Vielen Dank an Sapan Diwakar und andere. Diese Antwort hat mir geholfen. Ich habe einfach ein RelativeLayout ohne Fragment erstellt, das RelativeLayout als übergeordnete oder Gruppenansicht verwendet, diese Gruppenansicht in der zu ersetzenden Transaktion angegeben und es hat funktioniert.

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>

0

Überprüfen Sie Ihre Rahmenlayout-ID und ersetzen Sie sie wie folgt

fragmentTransactionChange = MainActivity.this.getSupportFragmentManager().beginTransaction();
fragmentTransactionChange.replace(R.id.progileframe, changeFragment);
fragmentTransactionChange.addToBackStack(null);
fragmentTransactionChange.commit();
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.