Separate Back Navigation für einen Tabbed View Pager in Android

Was ich möchte.

In einem Tab-Sliding-Menü-Kontext möchte ich ein Fragment zu einem anderen innerhalb einer Registerkarte ersetzen und das Tab-Menü und auch die aktuelle Registerkarte beibehalten. Beim Schieben auf eine andere Registerkarte und Rückkehr zum Original, möchte ich das letzte Fragment angezeigt werden.

Zum Beispiel habe ich tab_a mit Fragment_1 , tab_b mit Fragment_4 und tab_c mit Fragment_7 . Jetzt will ich einen Button in Fragment_1 das öffnet mich Fragment_2 , aber ich möchte in der Lage sein, um die Fragmente der tab_b und tab_c zu wischen. Und wenn ich auf tab_a zurückkehre, muss Fragment_2 angezeigt werden.

Bildbeschreibung hier eingeben

 MainActivity | | ContainerFragment | | |_ _ _ Tab A | |_ _ _ Fragment 1 | | | |_ _ _ Fragment 2 | | | |_ _ _ Fragment 3 | | | |_ _ _ ... | |_ _ _ Tab B | |_ _ _ Fragment 4 | | | |_ _ _ Fragment 5 | | | |_ _ _ Fragment 6 | | | |_ _ _ ... | |_ _ _ Tab C | |_ _ _ Fragment 7 | | | |_ _ _ Fragment 8 | | | |_ _ _ Fragment 8 | | | |_ _ _ ... 

Meine aktuelle Haupttätigkeit.

Xml

 <android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent"> <android.support.design.widget.AppBarLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"> <android.support.design.widget.TabLayout android:id="@+id/tabs" android:layout_width="match_parent" android:layout_height="wrap_content" app:tabMode="fixed" app:tabGravity="fill"/> </android.support.design.widget.AppBarLayout> <android.support.v4.view.ViewPager android:id="@+id/viewpager" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_behavior="@string/appbar_scrolling_view_behavior" /> </android.support.design.widget.CoordinatorLayout> 

Code

 public class MainActivity extends AppCompatActivity { private TabLayout tabLayout; private final static int[] tabIcons = { R.drawable.ic_tab_a, R.drawable.ic_tab_b, R.drawable.ic_tab_c }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ViewPager viewPager = (ViewPager) findViewById(R.id.viewpager); setupViewPager(viewPager); tabLayout = (TabLayout) findViewById(R.id.tabs); tabLayout.setupWithViewPager(viewPager); setupTabIcons(); } private void setupTabIcons() { tabLayout.getTabAt(0).setIcon(tabIcons[0]); tabLayout.getTabAt(1).setIcon(tabIcons[1]); tabLayout.getTabAt(2).setIcon(tabIcons[2]); } private void setupViewPager(ViewPager viewPager) { ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager()); adapter.addFrag(new Fragment1()); adapter.addFrag(new Fragment4()); adapter.addFrag(new Fragment7()); viewPager.setAdapter(adapter); } class ViewPagerAdapter extends FragmentPagerAdapter { private final List<Fragment> mFragmentList = new ArrayList<>(); ViewPagerAdapter(FragmentManager manager) { super(manager); } @Override public Fragment getItem(int position) { return mFragmentList.get(position); } @Override public int getCount() { return mFragmentList.size(); } void addFrag(Fragment fragment) { mFragmentList.add(fragment); } } } 

Fragmente

Xml

 <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:background="@android:color/holo_blue_light" android:id="@+id/fragment_1" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="myContext"> <Button android:text="Go to next Fragment" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerVertical="true" android:layout_centerHorizontal="true" android:id="@+id/button_nextFrag" /> <FrameLayout android:id="@+id/tab1_container" android:layout_width="match_parent" android:layout_height="match_parent"/> </RelativeLayout> 

Code

 public class Fragment1 extends Fragment { private void goNextFragment() { FragmentTransaction trans = getFragmentManager().beginTransaction(); trans.replace(R.id.tab1_container, new Fragment2()); trans.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN); trans.addToBackStack(null); trans.commit(); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Inflate the layout for this fragment. View root = inflater.inflate(R.layout.fragment_1, container, false); // Go to next Fragment Button. final Button nextFrag = (Button) root.findViewById(R.id.button_nextFrag); nextFrag .setOnClickListener(new View.OnClickListener() { public void onClick(View v) { goNextFragment(); } }); return root; } } 

Bearbeiten:

Ich habe einige Lösungen, aber keiner ist perfekt. Wenn ich eine Framelayaout in MainActivity setze, wird Fragment_1 korrekt in Fragment_2 , aber es ist auch in tab_b und tab_c . Wenn das FrameLayout in Fragment_1 , kann ich die anderen Tabs korrekt ausrollen, aber der Ersatz geht nicht gut, denn Fragment_2 ist geöffnet, aber Fragment_1 ist auch da.

  • Wie kann man in der Ansicht Pager in Android tippen?
  • ViewPager + FragmentStatePagerAdapter: ViewPager funktioniert nicht mehr, wenn die Bildschirmorientierung geändert wird
  • Android Sidebar wie Facebook oder Firefox
  • Mehrere Seiten zur gleichen Zeit auf einem ViewPager
  • Wie kann ich ViewPager layoutParams programmgesteuert einstellen?
  • ViewPager und Datenbank
  • 3 androide Fragmente im Viewpager, wie man sie alle am Leben hält?
  • Umgang mit Fragment und Ansicht Pager: kann nicht ändern Tag des Fragments AND Rekursive Eintrag zu executePendingTransactions
  • 3 Solutions collect form web for “Separate Back Navigation für einen Tabbed View Pager in Android”

    Sie können einen ViewPager zusammen mit einem TabLayout .

     <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <android.support.v4.view.ViewPager android:id="@+id/viewpager" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1"/> <android.support.design.widget.TabLayout android:id="@+id/tablayout" android:layout_width="match_parent" android:layout_height="wrap_content"/> </LinearLayout> 

    Erstellen Sie dann eine Klasse, die FragmentStatePagerAdapter , um den ViewPager mit Ihrem ursprünglichen Fragment zu initialisieren:

     public class CustomPagerAdapter extends FragmentStatePagerAdapter { private final List<String> tabTitles = new ArrayList<String>() {{ add("Fragment 1"); add("Fragment 4"); add("Fragment 7"); }}; private List<Fragment> tabs = new ArrayList<>(); public CustomPagerAdapter(FragmentManager fragmentManager) { super(fragmentManager); initializeTabs(); } private void initializeTabs() { tabs.add(HostFragment.newInstance(new Fragment1())); tabs.add(HostFragment.newInstance(new Fragment4())); tabs.add(HostFragment.newInstance(new Fragment7())); } @Override public Fragment getItem(int position) { return tabs.get(position); } @Override public int getCount() { return tabs.size(); } @Override public CharSequence getPageTitle(int position) { return tabTitles.get(position); } } 

    Die Fragmente, die den tatsächlichen Inhalt enthalten, sollten von einem HostFragment verpackt werden, das sein Kind FragmentManager , um das aktuelle Fragment durch ein neues zu ersetzen, wenn du navigierst oder das letzte Fragment aus dem Fragmentstapel kommst. Rufen Sie das replaceFragment an, um zu navigieren:

     public class HostFragment extends BackStackFragment { private Fragment fragment; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { super.onCreateView(inflater, container, savedInstanceState); View view = inflater.inflate(R.layout.host_fragment, container, false); if (fragment != null) { replaceFragment(fragment, false); } return view; } public void replaceFragment(Fragment fragment, boolean addToBackstack) { if (addToBackstack) { getChildFragmentManager().beginTransaction().replace(R.id.hosted_fragment, fragment).addToBackStack(null).commit(); } else { getChildFragmentManager().beginTransaction().replace(R.id.hosted_fragment, fragment).commit(); } } public static HostFragment newInstance(Fragment fragment) { HostFragment hostFragment = new HostFragment(); hostFragment.fragment = fragment; return hostFragment; } } 

    Das HostFragment sollte die abstrakte Klasse BackstackFragment

     public abstract class BackStackFragment extends Fragment { public static boolean handleBackPressed(FragmentManager fm) { if(fm.getFragments() != null){ for(Fragment frag : fm.getFragments()){ if(frag != null && frag.isVisible() && frag instanceof BackStackFragment){ if(((BackStackFragment)frag).onBackPressed()){ return true; } } } } return false; } protected boolean onBackPressed() { FragmentManager fm = getChildFragmentManager(); if(handleBackPressed(fm)){ return true; } else if(getUserVisibleHint() && fm.getBackStackEntryCount() > 0){ fm.popBackStack(); return true; } return false; } } 

    Draht in der MainActivity :

     public class MainActivity extends AppCompatActivity { private CustomPagerAdapter customPagerAdapter; private ViewPager viewPager; private TabLayout tabLayout; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); viewPager = (ViewPager) findViewById(R.id.viewpager); tabLayout = (TabLayout) findViewById(R.id.tablayout); customPagerAdapter = new CustomPagerAdapter(getSupportFragmentManager()); // 2 is enough for us; increase if you have more tabs! viewPager.setOffscreenPageLimit(2); viewPager.setAdapter(customPagerAdapter); tabLayout.setupWithViewPager(viewPager); } @Override public void onBackPressed() { if(!BackStackFragment.handleBackPressed(getSupportFragmentManager())){ super.onBackPressed(); } } public void openNextFragment() { HostFragment hostFragment = (HostFragment) customPagerAdapter.getItem(viewPager.getCurrentItem()); // your logic to change the fragments... } } 

    Diese Lösung ist sicher nicht perfekt, aber die Arbeit wird erledigt. Lesen Sie mehr Flaum darüber in meinem Blog-Post auf dem Thema.

    Basierend auf dem, was Sie erklärt I Implementieren nach:

    1- In deiner Aktivität deine Tabs und ViewPager :

      mPager = (ViewPager) findViewById(R.id.vp_pager); mPager.setOffscreenPageLimit(3); PagerAdapter mAdapter = new PagerAdapter(getSupportFragmentManager(), getContext()); mPager.setAdapter(mAdapter); //tab.setupWithViewPager(mPager); 

    2- In jedem Tabs erstellen ViewPager (ich nehme an, Sie wollen Tabs innerhalb tabs wenn Sie nicht brauchen Tabs nur entfernt sie), Umsetzung der einzelnen fragment wäre so etwas wie:

      ViewPager mPager = (ViewPager) rootView.findViewById(R.id.vp_pager); mPager.setOffscreenPageLimit(3); CategoryAdapter mAdapter = new CategoryAdapter(getChildFragmentManager());//make sure this ChildFragmentManager mPager.setAdapter(mAdapter); 

    Auch im Fragment einen Button erstellen, der beim Klick auf ein anderes Fragment geht:

      button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { mPager.setCurrentItem(1); // go to second fragment } }); 

    Endgültiges Ergebnis wäre so etwas wie folgt und wann wenn du zu Home Tabs gehst und dann geht zurück zu Kategorie Tab du bist deine Fragment Position nicht geändert.

    Zwei Punkte, an die Sie sich erinnern sollten:

    1. Set mPager.setOffscreenPageLimit(3); Wenn du dein Fragment nicht zerstören willst
    2. Im inneren Fragment pass getChildFragmentManager() anstelle von FragmentManager()

    Bildbeschreibung hier eingeben

    Wenn Sie nicht brauchen Inner ViewPager Und Sie wollen nur laden eine Instanz von Fragment zur Zeit hier ist eine andere Option:

    Ich mache zuerst den vorherigen Weg.

    2- In deinem Fragment xml setze FrameContainer und lade dein Fragment darin ein:

      CategoryResultFragment f = CategoryResultFragment.newInstance(); getFragmentManager().beginTransaction() .replace(R.id.frame_result_container, f) .commit(); 

    Edit: Dies ist nicht der beste Ansatz, aber ich denke, lösen Sie Ihr Problem:

    1 Erstellen Sie ein statisches Feld in Ihrer MainActivity wie folgt:

     static String[] type = new String[3]; 

    2- Wenn Sie in Ihrem Fragment auf Click aufrufen, aktualisieren Sie den String Wert in Ihrem MainActivity .

     public static update currentType(int pos,String type); 

    Erster Wert ist ViewPager Position, zweiter Wert ist dein innerer Fragmenttyp (zB: fragment_d);

    3- in deinem ViewPager

      @Override public Fragment getItem(int position) { switch (position) { case 0: // first tab if(type[position] == "fragment_d") return new Fragment_D(); else return new Fragment_B(); } } 

    Sie können Fragmente innerhalb des Seitenfragments ändern. Zum Beispiel implementiert TAB_A die Logik des Kommissionierfragments 1 oder 2 und zeigt das ausgewählte Fragment im Inneren an. Hierarchie sieht aus wie:

    ViewPager -> TAB_A -> Fragment 1 oder 2 (in TAB_A anzeigen).

    Auch sollten Sie getChildFragmentManager () verwenden, um Fragmente innerhalb von TAB_A zu verwalten.

    Das Android ist ein Google Android Fan-Website, Alles ├╝ber Android Phones, Android Wear, Android Dev und Android Spiele Apps und so weiter.