29

Ich habe eine Aktivität, die zunächst einen ViewPager hostet, der an einen FragmentPagerAdapter angeschlossen ist.ViewPager durch Fragment ersetzen - Dann zurück navigieren

Wenn der Benutzer auf ein Element im Child-Fragment des ViewPagers klickt, verwende ich eine FragmentTransaction, um eine leere Containeransicht durch ein neues Fragment zu ersetzen, zu dem ich navigieren möchte.

Wenn ich addToBackStack() für die Transaktion verwende, die Transaktion festschreibe und dann zurück navigiere, komme ich nicht zu den ViewPager-Ansichten zurück (das ursprüngliche Layout).

Wenn ich addToBackStack() für die Transaktion nicht verwende, die Transaktion festschreibe und dann zurück navigiere, wird die Anwendung beendet.

Es scheint offensichtlich, dass der ViewPager nicht zum Backstack hinzugefügt wird (was nicht so überraschend ist, da es kein Fragment an sich ist). Aber ich würde erwarten, dass das Zurückdrücken mich zurücknimmt zu dieser Aktivität initial View (der ViewPager).

Basierend auf dem, was ich gelesen habe, scheint es, dass der ViewPager oder PagerAdapter, vielleicht weil eine Fragmenttransaktion stattfindet, den Überblick darüber verliert, welches Fragment angezeigt werden soll.

Ich bin wirklich mit diesem verwirrt, aber ich endete damit, eine riesige Unordnung des Codes zu schaffen, der onBackPress überschreibt und die viewpager Ansichten zeigt und versteckt. Ich hätte gedacht, dass es eine einfachere Möglichkeit gibt, Standardverhalten zu verwenden, um die entsprechende Navigation auszuführen.

tl; dr

A ein Viewpager Hosting-Fragmente. B ist ein neues Fragment.

Wenn ich A durch B ersetze und dann zurück drücke, gehe ich zurück zu A, aber das passiert nicht.

Jeder Rat würde sehr geschätzt werden.

Code:

MainActivity:

@Override 
     public void onCreate(Bundle savedInstanceState) { 
      super.onCreate(savedInstanceState); 
      setContentView(R.layout.main); 

     headingLayout = (RelativeLayout) findViewById(R.id.headingLayout); 
     headingLayout.setVisibility(View.GONE); 

     // Set up the ViewPager, attaching the adapter and setting up a listener 
     // for when the 
     // user swipes between sections. 
     mViewPager = (ViewPager) findViewById(R.id.pager); 

     mViewPager.setPageMargin(8); 

     /** Getting fragment manager */ 
     FragmentManager fm = getSupportFragmentManager(); 

     /** Instantiating FragmentPagerAdapter */ 
     MyFragmentPagerAdapter pagerAdapter = new MyFragmentPagerAdapter(fm); 

     /** Setting the pagerAdapter to the pager object */ 
     mViewPager.setAdapter(pagerAdapter); 
. 
. 
. 
} 

    public void onListItemClicked(Fragment fragment) { 
     fromPlayer = false; 
     InitiateTransaction(fragment, true); 

    } 


    public void InitiateTransaction(Fragment fragment, boolean addToBackStack) { 

     invalidateOptionsMenu(); 

     FragmentManager fm = getSupportFragmentManager(); 
     FragmentTransaction ft = fm.beginTransaction(); 

     ft.replace(R.id.fragmentContainer, fragment).addToBackStack(null) 
       .commit(); 

    } 

PagerAdapter:

package another.music.player; 

import android.os.Bundle; 
import android.support.v4.app.Fragment; 
import android.support.v4.app.FragmentManager; 
import android.support.v4.app.FragmentPagerAdapter; 
import another.music.player.fragments.AlbumListFragment; 
import another.music.player.fragments.ArtistListFragment; 
import another.music.player.fragments.SongListFragment; 

public class MyFragmentPagerAdapter extends FragmentPagerAdapter { 

    final int PAGE_COUNT = 3; 

    /** Constructor of the class */ 
    public MyFragmentPagerAdapter(FragmentManager fm) { 
     super(fm); 
    } 

    /** This method will be invoked when a page is requested to create */ 
    @Override 
    public Fragment getItem(int i) { 
     switch (i) { 
     case 0: 
      ArtistListFragment artistListFragment = new ArtistListFragment(); 
      Bundle artistData = new Bundle(); 
      artistData.putInt("current_page", i + 1); 
      artistListFragment.setArguments(artistData); 
      return artistListFragment; 

     case 1: 
      AlbumListFragment albumListFragment = new AlbumListFragment(); 
      Bundle albumData = new Bundle(); 
      albumData.putInt("current_page", i + 1); 
      albumData.putBoolean("showHeader", false); 
      albumListFragment.setArguments(albumData); 
      return albumListFragment; 

     default: 

      SongListFragment songListFragment = new SongListFragment(); 
      Bundle songData = new Bundle(); 
      songData.putInt("current_page", i + 1); 
      songListFragment.setArguments(songData); 
      return songListFragment; 
     } 
    } 

    /** Returns the number of pages */ 
    @Override 
    public int getCount() { 
     return PAGE_COUNT; 
    } 

    @Override 
    public CharSequence getPageTitle(int position) { 
     switch (position) { 
     case 0: 
      return "Artists"; 

     case 1: 
      return "Albums"; 

     default: 
      return "Songs"; 
     } 
    } 
} 

Haupt XML (enthaltend fragmentContainer & ViewPager):

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:tools="http://schemas.android.com/tools" 
    android:id="@+id/main_layout" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:background="@drawable/app_background_ics" > 

    <RelativeLayout 
     android:id="@+id/headingLayout" 
     android:layout_width="match_parent" 
     android:layout_height="56dp" > 
    </RelativeLayout> 

    <FrameLayout 
     android:id="@+id/fragmentContainer" 
     android:layout_width="fill_parent" 
     android:layout_height="fill_parent" 
     android:layout_below="@+id/headingLayout" /> 

    <android.support.v4.view.ViewPager 
     android:id="@+id/pager" 
     android:layout_width="fill_parent" 
     android:layout_height="fill_parent" > 

     <android.support.v4.view.PagerTabStrip 
      android:id="@+id/pager_title_strip" 
      android:layout_width="match_parent" 
      android:layout_height="wrap_content" 
      android:background="#33b5e5" 
      android:paddingBottom="4dp" 
      android:paddingTop="4dp" 
      android:textColor="#fff" /> 
    </android.support.v4.view.ViewPager> 

</RelativeLayout> 

Antwort

3

Der einzige Weg, den ich gefunden habe, ist folgendes:

Wenn Sie vom viewPager weg navigieren, senden Sie den viewPager mit Visiblity.GONE aus dem Blick. Fügen Sie dem Backstack beliebige Fragmenttransaktionen hinzu.

Wenn Sie zum viewPager-Bildschirm zurückkehren (über einen Zurückdruck), überschreiben Sie onBackPressed. Sie können überprüfen, wie viele Fragmente sich im Backstack befinden. Wenn der viewPager die erste Ansicht war, bevor Fragmenttransaktionen stattfanden, können Sie überprüfen, ob die Anzahl der Fragmentbackstack-Einträge 0 ist.

fragmentManager.getBackStackEntryCount() == 0, im Backstack sind keine Fragmente vorhanden.

Wenn diese Aussage wahr ist, dann bringen Sie den viewPager einfach wieder mit Visibility.VISIBLE in Sicht.

+1

YES! Vielen Dank. –

33

Ich hatte auch das gleiche Problem für eine lange Zeit. Die Lösung erweist sich als sehr einfach und Sie benötigen keine Hacks mit der Sichtbarkeit von ViewPager. Ich werde in dieser anderen SO bezogenen Frage beschrieben: Fragment in ViewPager not restored after popBackStack

Um es jedoch einfach zu machen, alles, was Sie brauchen, ist getChildFragmentManager() in Ihrem ViewPager-Adapter anstelle von getSupportFragmentManager(). Anstatt also diese:

/** Getting fragment manager */ 
    FragmentManager fm = getSupportFragmentManager(); 

    /** Instantiating FragmentPagerAdapter */ 
    MyFragmentPagerAdapter pagerAdapter = new MyFragmentPagerAdapter(fm); 

    /** Setting the pagerAdapter to the pager object */ 
    mViewPager.setAdapter(pagerAdapter); 

Sie tun dies:

/** Getting fragment manager */ 
    FragmentManager fm = getChildFragmentManager(); 

    /** Instantiating FragmentPagerAdapter */ 
    MyFragmentPagerAdapter pagerAdapter = new MyFragmentPagerAdapter(fm); 

    /** Setting the pagerAdapter to the pager object */ 
    mViewPager.setAdapter(pagerAdapter); 
+9

getChildFragmentManager() ist in Ordnung, wenn Ihr ViewPager in einem Fragment gehostet wird, aber nicht, wenn der ViewPager in einer FragmentActivity gehostet wird. –

+0

Gern geschehen :) –

9

UPDATE:
Das ist nicht die „Android Art und Weise“, und es führt zu einer schlechten Benutzererfahrung für den Fall einer Listenansicht . Erstellen Sie stattdessen eine neue Aktivität.

Für Leute, die nach einer einfachen Lösung für dieses Problem suchen, werde ich nur zusammenfassen, was ich getan habe.

Meine Architektur:

  • ViewPager in FragmentActivity (ActionBarActivity eigentlich für ActionBar Unterstützung Aber ActionBarActivity implementiert FragmentActivity.).

  • 2 Registerkarten:

    • FragmentContainer1 das Fragment erstreckt.
    • FragmentContainer2, das Fragment erweitert.

Für jeden FragmentContainer, nennen wir getChildFragmentManager im onCreate Verfahren zum Beispiel, und fügen Sie das Fragment wir in diesem Container zeigen wollen:

FragmentToShow fragment = new FragmentToShow(); 

getChildFragmentManager() 
     .beginTransaction() 
     .add(R.id.container, fragment) 
     .commit(); 

Wir wollen nicht unsere erste Fragment, das dem Backstack des Fragmentcontainers hinzugefügt werden soll, da wir den Fragmentcontainer nicht anzeigen möchten, wenn wir auf den Zurück-Button klicken.

Wenn wir dann FragmentToShow von einem anderen Fragmente in unserer FragmentToShow Klasse (wie mit einem Listview) ersetzt werden sollen:

Fragment itemFragment = new ItemFragment(); 

getFragmentManager() 
     .beginTransaction() 
     .replace(R.id.container, itemFragment) 
     .addToBackStack(null) 
     .commit(); 

Hier holen wir das Kind Fragment-Manager, und wir fügen die itemFragment auf die Rückseite Stapel .

Nun wollen wir, durch Drücken der Zurück-Taste, zurück zum listView (der FragmentToShow-Instanz) gehen. Unsere Tätigkeit (FragmentActivity) ist der einzige bewusst die Zurück-Taste, so haben wir die Methode zu überschreiben onBackPressed() in dieser Aktivität:

@Override 
public void onBackPressed() { 

    // We retrieve the fragment manager of the activity 
    FragmentManager frgmtManager = getSupportFragmentManager(); 

    // We retrieve the fragment container showed right now 
    // The viewpager assigns tags to fragment automatically like this 
    // mPager is our ViewPager instance 
    Fragment fragment = frgmtManager.findFragmentByTag("android:switcher:" + mPager.getId() + ":" + mPager.getCurrentItem()); 

    // And thanks to the fragment container, we retrieve its child fragment manager 
    // holding our fragment in the back stack 
    FragmentManager childFragmentManager = fragment.getChildFragmentManager(); 

    // And here we go, if the back stack is empty, we let the back button doing its job 
    // Otherwise, we show the last entry in the back stack (our FragmentToShow) 
    if(childFragmentManager.getBackStackEntryCount() == 0){ 
     super.onBackPressed(); 
    } else { 
     childFragmentManager.popBackStack(); 
    } 
} 

Da wir getSupportFragmentManager in unserer Tätigkeit nennen, können wir einfach getFragmentManager rufen in unsere Kinderfragmente. Dies wird eine FragmentManager-Instanz unterstützen.

Und das war's! Ich bin kein Experte, also wenn Sie Anregungen oder Anmerkungen haben, fühlen Sie sich frei.

+0

Vielen Dank onBackPressed() funktioniert gut. – Androidbirt

+0

Diese Architektur arbeitet für mich. Danke :) – Dory

0

Wenn Sie mit einem ViewPagerFragments enthält, die Activities starten können, ist hier, wie Sie richtig zurück in die Position in der ViewPager navigieren würde, auf Rücken schlagen oder von der Activity Navigation nach oben (vorausgesetzt, dass Sie nach oben Navigation für deklariert haben Ihre Activities).

Zunächst müssen Sie die aktuelle Position der ViewPager als ein Extra in der Intent übergeben, um die neue Activity zu starten.

Dann werden Sie diese Position an die Mutter Activity tun dies passieren zurück:

Intent upIntent = NavUtils.getParentActivityIntent(this); 
upIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP); 
upIntent.putExtra(FeedPagerActivity.EXTRA_POSITION, position); 
NavUtils.navigateUpTo(this, upIntent); 

diesen Code Put innerhalb

onOptionsItemSelected (MenuItem Artikel)

+0

Sie sind Antwort war nicht klar, können Sie bitte einige Ideen oder verwandte Links geben, Danke für den Beitrag. –

0

Ich glaube, ich Ich hatte ein sehr ähnliches Problem.

Es scheint, dass FragmentManager s in etwas hierarchischer Weise verhalten. Die Art und Weise, wie ich dieses Problem gelöst habe, bestand darin, den "main" FragmentManager aus der Aktivität zu verwenden, die den Container und den ViewPager hostet und nicht den, der aus Fragmenten innerhalb des ViewPagers abgerufen werden kann.

this.getActivity().getSupportFragmentManager() 

wo this ist eine Instanz Fragment:

Um dies zu tun, habe ich verwendet.

Wenn ich nun von einem Element im ViewPager zu einem anderen Fragment mit "Ersetzen" -Transaktion navigiere, kann ich den ViewPager in dem Zustand sehen, den ich verlassen habe.

Ausführlichere Codebeispiel sieht wie folgt aus:

FragmentManager fragmentManager = MyCurrentFragment.this.getActivity().getSupportFragmentManager(); 
FragmentTransaction transaction = fragmentManager.beginTransaction(); 

transaction.replace(R.id.container, newFragment); 
transaction.addToBackStack(null); 

transaction.commit(); 
Verwandte Themen