Reemplazar Fragmento dentro de una ViewPager

ViewPager usar Fragment con una ViewPager usando FragmentPagerAdapter . Lo que quiero lograr es reemplazar un fragmento, ubicado en la primera página de ViewPager , por otro.

El buscapersonas está compuesto de dos páginas. El primero es FirstPagerFragment , el segundo es SecondPagerFragment . Al hacer clic en un botón de la primera página. Me gustaría reemplazar FirstPagerFragment con NextFragment.

Ahí está mi código a continuación.

 public class FragmentPagerActivity extends FragmentActivity { static final int NUM_ITEMS = 2; MyAdapter mAdapter; ViewPager mPager; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.fragment_pager); mAdapter = new MyAdapter(getSupportFragmentManager()); mPager = (ViewPager) findViewById(R.id.pager); mPager.setAdapter(mAdapter); } /** * Pager Adapter */ public static class MyAdapter extends FragmentPagerAdapter { public MyAdapter(FragmentManager fm) { super(fm); } @Override public int getCount() { return NUM_ITEMS; } @Override public Fragment getItem(int position) { if(position == 0) { return FirstPageFragment.newInstance(); } else { return SecondPageFragment.newInstance(); } } } /** * Second Page FRAGMENT */ public static class SecondPageFragment extends Fragment { public static SecondPageFragment newInstance() { SecondPageFragment f = new SecondPageFragment(); return f; } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { //Log.d("DEBUG", "onCreateView"); return inflater.inflate(R.layout.second, container, false); } } /** * FIRST PAGE FRAGMENT */ public static class FirstPageFragment extends Fragment { Button button; public static FirstPageFragment newInstance() { FirstPageFragment f = new FirstPageFragment(); return f; } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { //Log.d("DEBUG", "onCreateView"); View root = inflater.inflate(R.layout.first, container, false); button = (Button) root.findViewById(R.id.button); button.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { FragmentTransaction trans = getFragmentManager().beginTransaction(); trans.replace(R.id.first_fragment_root_id, NextFragment.newInstance()); trans.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN); trans.addToBackStack(null); trans.commit(); } }); return root; } /** * Next Page FRAGMENT in the First Page */ public static class NextFragment extends Fragment { public static NextFragment newInstance() { NextFragment f = new NextFragment(); return f; } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { //Log.d("DEBUG", "onCreateView"); return inflater.inflate(R.layout.next, container, false); } } } 

… y aquí los archivos xml

fragment_pager.xml

      

first.xml

   

Ahora el problema … qué identificación debería usar en

 trans.replace(R.id.first_fragment_root_id, NextFragment.newInstance()); 

?

Si uso R.id.first_fragment_root_id , el reemplazo funciona, pero Hierarchy Viewer muestra un comportamiento extraño, como se muestra a continuación.

Al principio la situación es

después del reemplazo la situación es

Como puede ver que hay algo mal, espero encontrar el mismo estado que se muestra en la primera imagen después de reemplazar el fragmento.

Hay otra solución que no necesita modificar el código fuente de ViewPager y FragmentStatePagerAdapter , y funciona con la clase base FragmentPagerAdapter utilizada por el autor.

Me gustaría comenzar respondiendo la pregunta del autor sobre qué ID debe usar; es ID del contenedor, es decir, ID del buscador en sí mismo. Sin embargo, como probablemente se haya dado cuenta, usar esa ID en su código no causa nada. Explicaré por qué:

En primer lugar, para hacer que ViewPager las páginas, debe llamar a notifyDataSetChanged() que reside en la clase base de su adaptador.

En segundo lugar, ViewPager utiliza el método abstracto getItemPosition() para comprobar qué páginas deben destruirse y cuáles deben conservarse. La implementación predeterminada de esta función siempre devuelve POSITION_UNCHANGED , lo que hace que ViewPager mantenga todas las páginas actuales y, en consecuencia, no adjunte su nueva página. Por lo tanto, para hacer que el reemplazo de fragmentos funcione, getItemPosition() debe getItemPosition() en su adaptador y debe devolver POSITION_NONE cuando se le llame con un fragmento viejo, que se ocultará, como argumento.

Esto también significa que su adaptador siempre necesita saber qué fragmento se debe mostrar en la posición 0, FirstPageFragment o NextFragment . Una forma de hacerlo es suministrar un oyente al crear FirstPageFragment , que se llamará cuando sea momento de cambiar fragmentos. Sin embargo, creo que esto es una buena ViewPager , para permitir que su adaptador de fragmento maneje todos los conmutadores de fragmento y las llamadas a ViewPager y FragmentManager .

En tercer lugar, FragmentPagerAdapter almacena en caché los fragmentos utilizados por un nombre que se deriva de la posición, por lo que si hubiera un fragmento en la posición 0, no se reemplazará aunque la clase sea nueva. Hay dos soluciones, pero la más simple es usar la función remove() de FragmentTransaction , que también eliminará su etiqueta.

Eso fue mucho texto, aquí hay un código que debería funcionar en su caso:

 public class MyAdapter extends FragmentPagerAdapter { static final int NUM_ITEMS = 2; private final FragmentManager mFragmentManager; private Fragment mFragmentAtPos0; public MyAdapter(FragmentManager fm) { super(fm); mFragmentManager = fm; } @Override public Fragment getItem(int position) { if (position == 0) { if (mFragmentAtPos0 == null) { mFragmentAtPos0 = FirstPageFragment.newInstance(new FirstPageFragmentListener() { public void onSwitchToNextFragment() { mFragmentManager.beginTransaction().remove(mFragmentAtPos0).commit(); mFragmentAtPos0 = NextFragment.newInstance(); notifyDataSetChanged(); } }); } return mFragmentAtPos0; } else return SecondPageFragment.newInstance(); } @Override public int getCount() { return NUM_ITEMS; } @Override public int getItemPosition(Object object) { if (object instanceof FirstPageFragment && mFragmentAtPos0 instanceof NextFragment) return POSITION_NONE; return POSITION_UNCHANGED; } } public interface FirstPageFragmentListener { void onSwitchToNextFragment(); } 

Espero que esto ayude a cualquiera!

A partir del 13 de noviembre de 2012, reparar fragmentos en un ViewPager parece ser mucho más fácil. Google lanzó Android 4.2 con soporte para fragmentos nesteds, y también es compatible con la nueva biblioteca de soporte de Android v11, así que esto funcionará hasta 1.6.

Es muy similar a la forma normal de reemplazar un fragmento, excepto que usas getChildFragmentManager. Parece que funciona, excepto que la parte posterior del fragmento nested no aparece cuando el usuario hace clic en el botón Atrás. Según la solución en esa pregunta vinculada, debe llamar manualmente a popBackStackImmediate () en el administrador secundario del fragmento. Por lo tanto, debe sobrescribir onBackPressed () de la actividad de ViewPager donde obtendrá el fragmento actual de ViewPager y llamará a getChildFragmentManager (). PopBackStackImmediate () en él.

Obtener el Fragmento que se muestra actualmente es un poco hacky, usé esta solución sucia “android: switcher: VIEWPAGER_ID: INDEX”, pero también puedes hacer un seguimiento de todos los fragmentos del ViewPager como se explica en la segunda solución en esta página .

Así que aquí está mi código para un ViewPager con 4 ListViews con una vista detallada que se muestra en ViewPager cuando el usuario hace clic en una fila y con el botón Atrás funcionando. Intenté incluir solo el código relevante por razones de brevedad, así que deje un comentario si desea que la aplicación completa se cargue en GitHub.

HomeActivity.java

  public class HomeActivity extends SherlockFragmentActivity { FragmentAdapter mAdapter; ViewPager mPager; TabPageIndicator mIndicator; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); mAdapter = new FragmentAdapter(getSupportFragmentManager()); mPager = (ViewPager)findViewById(R.id.pager); mPager.setAdapter(mAdapter); mIndicator = (TabPageIndicator)findViewById(R.id.indicator); mIndicator.setViewPager(mPager); } // This the important bit to make sure the back button works when you're nesting fragments. Very hacky, all it takes is some Google engineer to change that ViewPager view tag to break this in a future Android update. @Override public void onBackPressed() { Fragment fragment = (Fragment) getSupportFragmentManager().findFragmentByTag("android:switcher:" + R.id.pager + ":"+mPager.getCurrentItem()); if (fragment != null) // could be null if not instantiated yet { if (fragment.getView() != null) { // Pop the backstack on the ChildManager if there is any. If not, close this activity as normal. if (!fragment.getChildFragmentManager().popBackStackImmediate()) { finish(); } } } } class FragmentAdapter extends FragmentPagerAdapter { public FragmentAdapter(FragmentManager fm) { super(fm); } @Override public Fragment getItem(int position) { switch (position) { case 0: return ListProductsFragment.newInstance(); case 1: return ListActiveSubstancesFragment.newInstance(); case 2: return ListProductFunctionsFragment.newInstance(); case 3: return ListCropsFragment.newInstance(); default: return null; } } @Override public int getCount() { return 4; } } } 

ListaProductosFragment.java

 public class ListProductsFragment extends SherlockFragment { private ListView list; public static ListProductsFragment newInstance() { ListProductsFragment f = new ListProductsFragment(); return f; } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View V = inflater.inflate(R.layout.list, container, false); list = (ListView)V.findViewById(android.R.id.list); list.setOnItemClickListener(new OnItemClickListener() { public void onItemClick(AdapterView parent, View view, int position, long id) { // This is important bit Fragment productDetailFragment = FragmentProductDetail.newInstance(); FragmentTransaction transaction = getChildFragmentManager().beginTransaction(); transaction.addToBackStack(null); transaction.replace(R.id.products_list_linear, productDetailFragment).commit(); } }); return V; } } 

Basado en la respuesta de @wize, que encontré útil y elegante, pude lograr lo que quería parcialmente, porque quería que la capacidad volviera al primer Fragmento una vez reemplazado. Lo logré modificando un poco su código.

Este sería el FragmentPagerAdapter:

 public static class MyAdapter extends FragmentPagerAdapter { private final class CalendarPageListener implements CalendarPageFragmentListener { public void onSwitchToNextFragment() { mFragmentManager.beginTransaction().remove(mFragmentAtPos0) .commit(); if (mFragmentAtPos0 instanceof FirstFragment){ mFragmentAtPos0 = NextFragment.newInstance(listener); }else{ // Instance of NextFragment mFragmentAtPos0 = FirstFragment.newInstance(listener); } notifyDataSetChanged(); } } CalendarPageListener listener = new CalendarPageListener();; private Fragment mFragmentAtPos0; private FragmentManager mFragmentManager; public MyAdapter(FragmentManager fm) { super(fm); mFragmentManager = fm; } @Override public int getCount() { return NUM_ITEMS; } @Override public int getItemPosition(Object object) { if (object instanceof FirstFragment && mFragmentAtPos0 instanceof NextFragment) return POSITION_NONE; if (object instanceof NextFragment && mFragmentAtPos0 instanceof FirstFragment) return POSITION_NONE; return POSITION_UNCHANGED; } @Override public Fragment getItem(int position) { if (position == 0) return Portada.newInstance(); if (position == 1) { // Position where you want to replace fragments if (mFragmentAtPos0 == null) { mFragmentAtPos0 = FirstFragment.newInstance(listener); } return mFragmentAtPos0; } if (position == 2) return Clasificacion.newInstance(); if (position == 3) return Informacion.newInstance(); return null; } } public interface CalendarPageFragmentListener { void onSwitchToNextFragment(); } 

Para ejecutar el reemplazo, simplemente defina un campo estático, del tipo CalendarPageFragmentListener e inicializado a través de los métodos newInstance de los fragmentos correspondientes y llame a FirstFragment.pageListener.onSwitchToNextFragment() o NextFragment.pageListener.onSwitchToNextFragment() respictevely.

Espero que sea claro y útil.
Atentamente.

Implementé una solución para:

  • Reemplazo de fragmento dynamic dentro de la pestaña
  • Mantenimiento del historial por pestaña
  • Trabajando con cambios de orientación

Los trucos para lograr esto son los siguientes:

  • Utilice el método notifyDataSetChanged () para aplicar el reemplazo de fragmentos
  • Utilice el administrador de fragmentos solo para backstage y no para reemplazo de fragement
  • Mantener la historia usando el patrón de memento (stack)

El código del adaptador es el siguiente:

 public class TabsAdapter extends FragmentStatePagerAdapter implements ActionBar.TabListener, ViewPager.OnPageChangeListener { /** The sherlock fragment activity. */ private final SherlockFragmentActivity mActivity; /** The action bar. */ private final ActionBar mActionBar; /** The pager. */ private final ViewPager mPager; /** The tabs. */ private List mTabs = new LinkedList(); /** The total number of tabs. */ private int TOTAL_TABS; private Map> history = new HashMap>(); /** * Creates a new instance. * * @param activity the activity * @param pager the pager */ public TabsAdapter(SherlockFragmentActivity activity, ViewPager pager) { super(activity.getSupportFragmentManager()); activity.getSupportFragmentManager(); this.mActivity = activity; this.mActionBar = activity.getSupportActionBar(); this.mPager = pager; mActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); } /** * Adds the tab. * * @param image the image * @param fragmentClass the class * @param args the arguments */ public void addTab(final Drawable image, final Class fragmentClass, final Bundle args) { final TabInfo tabInfo = new TabInfo(fragmentClass, args); final ActionBar.Tab tab = mActionBar.newTab(); tab.setTabListener(this); tab.setTag(tabInfo); tab.setIcon(image); mTabs.add(tabInfo); mActionBar.addTab(tab); notifyDataSetChanged(); } @Override public Fragment getItem(final int position) { final TabInfo tabInfo = mTabs.get(position); return Fragment.instantiate(mActivity, tabInfo.fragmentClass.getName(), tabInfo.args); } @Override public int getItemPosition(final Object object) { /* Get the current position. */ int position = mActionBar.getSelectedTab().getPosition(); /* The default value. */ int pos = POSITION_NONE; if (history.get(position).isEmpty()) { return POSITION_NONE; } /* Checks if the object exists in current history. */ for (Stack stack : history.values()) { TabInfo c = stack.peek(); if (c.fragmentClass.getName().equals(object.getClass().getName())) { pos = POSITION_UNCHANGED; break; } } return pos; } @Override public int getCount() { return mTabs.size(); } @Override public void onPageScrollStateChanged(int arg0) { } @Override public void onPageScrolled(int arg0, float arg1, int arg2) { } @Override public void onPageSelected(int position) { mActionBar.setSelectedNavigationItem(position); } @Override public void onTabSelected(final ActionBar.Tab tab, final FragmentTransaction ft) { TabInfo tabInfo = (TabInfo) tab.getTag(); for (int i = 0; i < mTabs.size(); i++) { if (mTabs.get(i).equals(tabInfo)) { mPager.setCurrentItem(i); } } } @Override public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction ft) { } @Override public void onTabReselected(ActionBar.Tab tab, FragmentTransaction ft) { } public void replace(final int position, final Class fragmentClass, final Bundle args) { /* Save the fragment to the history. */ mActivity.getSupportFragmentManager().beginTransaction().addToBackStack(null).commit(); /* Update the tabs. */ updateTabs(new TabInfo(fragmentClass, args), position); /* Updates the history. */ history.get(position).push(new TabInfo(mTabs.get(position).fragmentClass, mTabs.get(position).args)); notifyDataSetChanged(); } /** * Updates the tabs. * * @param tabInfo * the new tab info * @param position * the position */ private void updateTabs(final TabInfo tabInfo, final int position) { mTabs.remove(position); mTabs.add(position, tabInfo); mActionBar.getTabAt(position).setTag(tabInfo); } /** * Creates the history using the current state. */ public void createHistory() { int position = 0; TOTAL_TABS = mTabs.size(); for (TabInfo mTab : mTabs) { if (history.get(position) == null) { history.put(position, new Stack()); } history.get(position).push(new TabInfo(mTab.fragmentClass, mTab.args)); position++; } } /** * Called on back */ public void back() { int position = mActionBar.getSelectedTab().getPosition(); if (!historyIsEmpty(position)) { /* In case there is not any other item in the history, then finalize the activity. */ if (isLastItemInHistory(position)) { mActivity.finish(); } final TabInfo currentTabInfo = getPrevious(position); mTabs.clear(); for (int i = 0; i < TOTAL_TABS; i++) { if (i == position) { mTabs.add(new TabInfo(currentTabInfo.fragmentClass, currentTabInfo.args)); } else { TabInfo otherTabInfo = history.get(i).peek(); mTabs.add(new TabInfo(otherTabInfo.fragmentClass, otherTabInfo.args)); } } } mActionBar.selectTab(mActionBar.getTabAt(position)); notifyDataSetChanged(); } /** * Returns if the history is empty. * * @param position * the position * @return the flag if empty */ private boolean historyIsEmpty(final int position) { return history == null || history.isEmpty() || history.get(position).isEmpty(); } private boolean isLastItemInHistory(final int position) { return history.get(position).size() == 1; } /** * Returns the previous state by the position provided. * * @param position * the position * @return the tab info */ private TabInfo getPrevious(final int position) { TabInfo currentTabInfo = history.get(position).pop(); if (!history.get(position).isEmpty()) { currentTabInfo = history.get(position).peek(); } return currentTabInfo; } /** The tab info class */ private static class TabInfo { /** The fragment class. */ public Class fragmentClass; /** The args.*/ public Bundle args; /** * Creates a new instance. * * @param fragmentClass * the fragment class * @param args * the args */ public TabInfo(Class fragmentClass, Bundle args) { this.fragmentClass = fragmentClass; this.args = args; } @Override public boolean equals(final Object o) { return this.fragmentClass.getName().equals(o.getClass().getName()); } @Override public int hashCode() { return fragmentClass.getName() != null ? fragmentClass.getName().hashCode() : 0; } @Override public String toString() { return "TabInfo{" + "fragmentClass=" + fragmentClass + '}'; } } 

La primera vez que agregue todas las tabs, debemos llamar al método createHistory () para crear el historial inicial

 public void createHistory() { int position = 0; TOTAL_TABS = mTabs.size(); for (TabInfo mTab : mTabs) { if (history.get(position) == null) { history.put(position, new Stack()); } history.get(position).push(new TabInfo(mTab.fragmentClass, mTab.args)); position++; } } 

Cada vez que desee reemplazar un fragmento en una pestaña específica, invoque: replace (final int position, final Class fragmentClass, final Bundle args)

 /* Save the fragment to the history. */ mActivity.getSupportFragmentManager().beginTransaction().addToBackStack(null).commit(); /* Update the tabs. */ updateTabs(new TabInfo(fragmentClass, args), position); /* Updates the history. */ history.get(position).push(new TabInfo(mTabs.get(position).fragmentClass, mTabs.get(position).args)); notifyDataSetChanged(); 

En la parte posterior presionada debe llamar al método back ():

 public void back() { int position = mActionBar.getSelectedTab().getPosition(); if (!historyIsEmpty(position)) { /* In case there is not any other item in the history, then finalize the activity. */ if (isLastItemInHistory(position)) { mActivity.finish(); } final TabInfo currentTabInfo = getPrevious(position); mTabs.clear(); for (int i = 0; i < TOTAL_TABS; i++) { if (i == position) { mTabs.add(new TabInfo(currentTabInfo.fragmentClass, currentTabInfo.args)); } else { TabInfo otherTabInfo = history.get(i).peek(); mTabs.add(new TabInfo(otherTabInfo.fragmentClass, otherTabInfo.args)); } } } mActionBar.selectTab(mActionBar.getTabAt(position)); notifyDataSetChanged(); } 

La solución funciona con la barra de acción sherlock y con un gesto de deslizamiento.

tl; dr: utiliza un fragmento de host que es responsable de reemplazar su contenido alojado y realiza un seguimiento de un historial de navegación posterior (como en un navegador).

Como su caso de uso consiste en una cantidad fija de tabs, mi solución funciona bien: la idea es llenar el ViewPager con instancias de una clase personalizada HostFragment , que puede reemplazar su contenido alojado y mantener su propio historial de navegación. Para reemplazar el fragmento alojado, realice una llamada al método hostfragment.replaceFragment() :

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

Todo lo que hace el método es reemplazar el diseño del marco con el ID R.id.hosted_fragment con el fragmento proporcionado al método.

¡Consulte mi tutorial sobre este tema para obtener más detalles y un ejemplo de trabajo completo en GitHub!

Algunas de las soluciones presentadas me ayudaron mucho a resolver parcialmente el problema, pero aún falta algo importante en las soluciones que ha producido excepciones inesperadas y contenido de páginas negras en lugar de fragmentos en algunos casos.

Lo que pasa es que la clase FragmentPagerAdapter usa la identificación del elemento para almacenar fragmentos en caché en FragmentManager . Por este motivo, debe sobrescribir también el método getItemId (int position) para que devuelva, por ejemplo, posición para las páginas de nivel superior y 100 + posición para las páginas de detalles. De lo contrario, el fragmento de nivel superior creado anteriormente se devolverá desde la memoria caché en lugar de un fragmento de nivel de detalle.

Además, estoy compartiendo aquí un ejemplo completo de cómo implementar tabs como actividad con páginas de Fragment utilizando ViewPager y botones de tabs usando RadioGroup que permite el reemplazo de páginas de nivel superior con páginas detalladas y también admite el botón Atrás. Esta implementación admite solo un nivel de astackmiento posterior (lista de elementos – detalles del artículo) pero la implementación de astackmiento posterior multinivel es sencilla. Este ejemplo funciona bastante bien en casos normales, excepto que arroja una NullPointerException en caso de que cambie a, por ejemplo, la segunda página, cambie el fragmento de la primera página (mientras no esté visible) y regrese a la primera página. Voy a publicar una solución a este problema una vez que lo resuelva:

 public class TabsActivity extends FragmentActivity { public static final int PAGE_COUNT = 3; public static final int FIRST_PAGE = 0; public static final int SECOND_PAGE = 1; public static final int THIRD_PAGE = 2; /** * Opens a new inferior page at specified tab position and adds the current page into back * stack. */ public void startPage(int position, Fragment content) { // Replace page adapter fragment at position. mPagerAdapter.start(position, content); } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Initialize basic layout. this.setContentView(R.layout.tabs_activity); // Add tab fragments to view pager. { // Create fragments adapter. mPagerAdapter = new PagerAdapter(pager); ViewPager pager = (ViewPager) super.findViewById(R.id.tabs_view_pager); pager.setAdapter(mPagerAdapter); // Update active tab in tab bar when page changes. pager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() { @Override public void onPageScrolled(int index, float value, int nextIndex) { // Not used. } @Override public void onPageSelected(int index) { RadioGroup tabs_radio_group = (RadioGroup) TabsActivity.this.findViewById( R.id.tabs_radio_group); switch (index) { case 0: { tabs_radio_group.check(R.id.first_radio_button); } break; case 1: { tabs_radio_group.check(R.id.second_radio_button); } break; case 2: { tabs_radio_group.check(R.id.third_radio_button); } break; } } @Override public void onPageScrollStateChanged(int index) { // Not used. } }); } // Set "tabs" radio group on checked change listener that changes the displayed page. RadioGroup radio_group = (RadioGroup) this.findViewById(R.id.tabs_radio_group); radio_group.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() { @Override public void onCheckedChanged(RadioGroup radioGroup, int id) { // Get view pager representing tabs. ViewPager view_pager = (ViewPager) TabsActivity.this.findViewById(R.id.tabs_view_pager); if (view_pager == null) { return; } // Change the active page. switch (id) { case R.id.first_radio_button: { view_pager.setCurrentItem(FIRST_PAGE); } break; case R.id.second_radio_button: { view_pager.setCurrentItem(SECOND_PAGE); } break; case R.id.third_radio_button: { view_pager.setCurrentItem(THIRD_PAGE); } break; } }); } } @Override public void onBackPressed() { if (!mPagerAdapter.back()) { super.onBackPressed(); } } /** * Serves the fragments when paging. */ private class PagerAdapter extends FragmentPagerAdapter { public PagerAdapter(ViewPager container) { super(TabsActivity.this.getSupportFragmentManager()); mContainer = container; mFragmentManager = TabsActivity.this.getSupportFragmentManager(); // Prepare "empty" list of fragments. mFragments = new ArrayList(){}; mBackFragments = new ArrayList(){}; for (int i = 0; i < PAGE_COUNT; i++) { mFragments.add(null); mBackFragments.add(null); } } /** * Replaces the view pager fragment at specified position. */ public void replace(int position, Fragment fragment) { // Get currently active fragment. Fragment old_fragment = mFragments.get(position); if (old_fragment == null) { return; } // Replace the fragment using transaction and in underlaying array list. // NOTE .addToBackStack(null) doesn't work this.startUpdate(mContainer); mFragmentManager.beginTransaction().setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN) .remove(old_fragment).add(mContainer.getId(), fragment) .commit(); mFragments.set(position, fragment); this.notifyDataSetChanged(); this.finishUpdate(mContainer); } /** * Replaces the fragment at specified position and stores the current fragment to back stack * so it can be restored by #back(). */ public void start(int position, Fragment fragment) { // Remember current fragment. mBackFragments.set(position, mFragments.get(position)); // Replace the displayed fragment. this.replace(position, fragment); } /** * Replaces the current fragment by fragment stored in back stack. Does nothing and returns * false if no fragment is back-stacked. */ public boolean back() { int position = mContainer.getCurrentItem(); Fragment fragment = mBackFragments.get(position); if (fragment == null) { // Nothing to go back. return false; } // Restore the remembered fragment and remove it from back fragments. this.replace(position, fragment); mBackFragments.set(position, null); return true; } /** * Returns fragment of a page at specified position. */ @Override public Fragment getItem(int position) { // If fragment not yet initialized, create its instance. if (mFragments.get(position) == null) { switch (position) { case FIRST_PAGE: { mFragments.set(FIRST_PAGE, new DefaultFirstFragment()); } break; case SECOND_PAGE: { mFragments.set(SECOND_PAGE, new DefaultSecondFragment()); } break; case THIRD_PAGE: { mFragments.set(THIRD_PAGE, new DefaultThirdFragment()); } break; } } // Return fragment instance at requested position. return mFragments.get(position); } /** * Custom item ID resolution. Needed for proper page fragment caching. * @see FragmentPagerAdapter#getItemId(int). */ @Override public long getItemId(int position) { // Fragments from second level page hierarchy have their ID raised above 100. This is // important to FragmentPagerAdapter because it is caching fragments to FragmentManager with // this item ID key. Fragment item = mFragments.get(position); if (item != null) { if ((item instanceof NewFirstFragment) || (item instanceof NewSecondFragment) || (item instanceof NewThirdFragment)) { return 100 + position; } } return position; } /** * Returns number of pages. */ @Override public int getCount() { return mFragments.size(); } @Override public int getItemPosition(Object object) { int position = POSITION_UNCHANGED; if ((object instanceof DefaultFirstFragment) || (object instanceof NewFirstFragment)) { if (object.getClass() != mFragments.get(FIRST_PAGE).getClass()) { position = POSITION_NONE; } } if ((object instanceof DefaultSecondragment) || (object instanceof NewSecondFragment)) { if (object.getClass() != mFragments.get(SECOND_PAGE).getClass()) { position = POSITION_NONE; } } if ((object instanceof DefaultThirdFragment) || (object instanceof NewThirdFragment)) { if (object.getClass() != mFragments.get(THIRD_PAGE).getClass()) { position = POSITION_NONE; } } return position; } private ViewPager mContainer; private FragmentManager mFragmentManager; /** * List of page fragments. */ private List mFragments; /** * List of page fragments to return to in onBack(); */ private List mBackFragments; } /** * Tab fragments adapter. */ private PagerAdapter mPagerAdapter; } 

I have created a ViewPager with 3 elements and 2 sub elements for index 2 and 3 and here what I wanted to do..

enter image description here

I have implemented this with the help from previous questions and answers from StackOverFlow and here is the link.

ViewPagerChildFragments

To replace a fragment inside a ViewPager you can move source codes of ViewPager , PagerAdapter and FragmentStatePagerAdapter classes into your project and add following code.

into ViewPager :

 public void notifyItemChanged(Object oldItem, Object newItem) { if (mItems != null) { for (ItemInfo itemInfo : mItems) { if (itemInfo.object.equals(oldItem)) { itemInfo.object = newItem; } } } invalidate(); } 

into FragmentStatePagerAdapter:

 public void replaceFragmetns(ViewPager container, Fragment oldFragment, Fragment newFragment) { startUpdate(container); // remove old fragment if (mCurTransaction == null) { mCurTransaction = mFragmentManager.beginTransaction(); } int position = getFragmentPosition(oldFragment); while (mSavedState.size() <= position) { mSavedState.add(null); } mSavedState.set(position, null); mFragments.set(position, null); mCurTransaction.remove(oldFragment); // add new fragment while (mFragments.size() <= position) { mFragments.add(null); } mFragments.set(position, newFragment); mCurTransaction.add(container.getId(), newFragment); finishUpdate(container); // ensure getItem returns newFragemtn after calling handleGetItemInbalidated() handleGetItemInbalidated(container, oldFragment, newFragment); container.notifyItemChanged(oldFragment, newFragment); } protected abstract void handleGetItemInbalidated(View container, Fragment oldFragment, Fragment newFragment); protected abstract int getFragmentPosition(Fragment fragment); 

handleGetItemInvalidated() ensures that after next call of getItem() it return newFragment getFragmentPosition() returns position of the fragment in your adapter.

Now, to replace fragments call

 mAdapter.replaceFragmetns(mViewPager, oldFragment, newFragment); 

If you interested in an example project ask me for the sources.

Works Great with AndroidTeam’s solution, however I found that I needed the ability to go back much like FrgmentTransaction.addToBackStack(null) But merely adding this will only cause the Fragment to be replaced without notifying the ViewPager. Combining the provided solution with this minor enhancement will allow you to return to the previous state by merely overriding the activity’s onBackPressed() method. The biggest drawback is that it will only go back one at a time which may result in multiple back clicks

 private ArrayList bFragments = new ArrayList(); private ArrayList bPosition = new ArrayList(); public void replaceFragmentsWithBackOut(ViewPager container, Fragment oldFragment, Fragment newFragment) { startUpdate(container); // remove old fragment if (mCurTransaction == null) { mCurTransaction = mFragmentManager.beginTransaction(); } int position = getFragmentPosition(oldFragment); while (mSavedState.size() <= position) { mSavedState.add(null); } //Add Fragment to Back List bFragments.add(oldFragment); //Add Pager Position to Back List bPosition.add(position); mSavedState.set(position, null); mFragments.set(position, null); mCurTransaction.remove(oldFragment); // add new fragment while (mFragments.size() <= position) { mFragments.add(null); } mFragments.set(position, newFragment); mCurTransaction.add(container.getId(), newFragment); finishUpdate(container); // ensure getItem returns newFragemtn after calling handleGetItemInbalidated() handleGetItemInvalidated(container, oldFragment, newFragment); container.notifyItemChanged(oldFragment, newFragment); } public boolean popBackImmediate(ViewPager container){ int bFragSize = bFragments.size(); int bPosSize = bPosition.size(); if(bFragSize>0 && bPosSize>0){ if(bFragSize==bPosSize){ int last = bFragSize-1; int position = bPosition.get(last); //Returns Fragment Currently at this position Fragment replacedFragment = mFragments.get(position); Fragment originalFragment = bFragments.get(last); this.replaceFragments(container, replacedFragment, originalFragment); bPosition.remove(last); bFragments.remove(last); return true; } } return false; } 

Espero que esto ayude a alguien.

Also as far as getFragmentPosition() goes it’s pretty much getItem() in reverse. You know which fragments go where, just make sure you return the correct position it will be in. Here’s an example:

  @Override protected int getFragmentPosition(Fragment fragment) { if(fragment.equals(originalFragment1)){ return 0; } if(fragment.equals(replacementFragment1)){ return 0; } if(fragment.equals(Fragment2)){ return 1; } return -1; } 

I also made a solution, which is working with Stacks . It’s a more modular approach so u don’t have to specify each Fragment and Detail Fragment in your FragmentPagerAdapter . It’s build on top of the Example from ActionbarSherlock which derives if I’m right from the Google Demo App.

 /** * This is a helper class that implements the management of tabs and all * details of connecting a ViewPager with associated TabHost. It relies on a * trick. Normally a tab host has a simple API for supplying a View or * Intent that each tab will show. This is not sufficient for switching * between pages. So instead we make the content part of the tab host * 0dp high (it is not shown) and the TabsAdapter supplies its own dummy * view to show as the tab content. It listens to changes in tabs, and takes * care of switch to the correct paged in the ViewPager whenever the selected * tab changes. * * Changed to support more Layers of fragments on each Tab. * by sebnapi (2012) * */ public class TabsAdapter extends FragmentPagerAdapter implements TabHost.OnTabChangeListener, ViewPager.OnPageChangeListener { private final Context mContext; private final TabHost mTabHost; private final ViewPager mViewPager; private ArrayList mTabTags = new ArrayList(); private HashMap> mTabStackMap = new HashMap>(); static final class TabInfo { public final String tag; public final Class clss; public Bundle args; TabInfo(String _tag, Class _class, Bundle _args) { tag = _tag; clss = _class; args = _args; } } static class DummyTabFactory implements TabHost.TabContentFactory { private final Context mContext; public DummyTabFactory(Context context) { mContext = context; } @Override public View createTabContent(String tag) { View v = new View(mContext); v.setMinimumWidth(0); v.setMinimumHeight(0); return v; } } public interface SaveStateBundle{ public Bundle onRemoveFragment(Bundle outState); } public TabsAdapter(FragmentActivity activity, TabHost tabHost, ViewPager pager) { super(activity.getSupportFragmentManager()); mContext = activity; mTabHost = tabHost; mViewPager = pager; mTabHost.setOnTabChangedListener(this); mViewPager.setAdapter(this); mViewPager.setOnPageChangeListener(this); } /** * Add a Tab which will have Fragment Stack. Add Fragments on this Stack by using * addFragment(FragmentManager fm, String _tag, Class _class, Bundle _args) * The Stack will hold always the default Fragment u add here. * * DON'T ADD Tabs with same tag, it's not beeing checked and results in unexpected * beahvior. * * @param tabSpec * @param clss * @param args */ public void addTab(TabHost.TabSpec tabSpec, Class clss, Bundle args){ Stack tabStack = new Stack(); tabSpec.setContent(new DummyTabFactory(mContext)); mTabHost.addTab(tabSpec); String tag = tabSpec.getTag(); TabInfo info = new TabInfo(tag, clss, args); mTabTags.add(tag); // to know the position of the tab tag tabStack.add(info); mTabStackMap.put(tag, tabStack); notifyDataSetChanged(); } /** * Will add the Fragment to Tab with the Tag _tag. Provide the Class of the Fragment * it will be instantiated by this object. Proivde _args for your Fragment. * * @param fm * @param _tag * @param _class * @param _args */ public void addFragment(FragmentManager fm, String _tag, Class _class, Bundle _args){ TabInfo info = new TabInfo(_tag, _class, _args); Stack tabStack = mTabStackMap.get(_tag); Fragment frag = fm.findFragmentByTag("android:switcher:" + mViewPager.getId() + ":" + mTabTags.indexOf(_tag)); if(frag instanceof SaveStateBundle){ Bundle b = new Bundle(); ((SaveStateBundle) frag).onRemoveFragment(b); tabStack.peek().args = b; } tabStack.add(info); FragmentTransaction ft = fm.beginTransaction(); ft.remove(frag).commit(); notifyDataSetChanged(); } /** * Will pop the Fragment added to the Tab with the Tag _tag * * @param fm * @param _tag * @return */ public boolean popFragment(FragmentManager fm, String _tag){ Stack tabStack = mTabStackMap.get(_tag); if(tabStack.size()>1){ tabStack.pop(); Fragment frag = fm.findFragmentByTag("android:switcher:" + mViewPager.getId() + ":" + mTabTags.indexOf(_tag)); FragmentTransaction ft = fm.beginTransaction(); ft.remove(frag).commit(); notifyDataSetChanged(); return true; } return false; } public boolean back(FragmentManager fm) { int position = mViewPager.getCurrentItem(); return popFragment(fm, mTabTags.get(position)); } @Override public int getCount() { return mTabStackMap.size(); } @Override public int getItemPosition(Object object) { ArrayList> positionNoneHack = new ArrayList>(); for(Stack tabStack: mTabStackMap.values()){ positionNoneHack.add(tabStack.peek().clss); } // if the object class lies on top of our stacks, we return default if(positionNoneHack.contains(object.getClass())){ return POSITION_UNCHANGED; } return POSITION_NONE; } @Override public Fragment getItem(int position) { Stack tabStack = mTabStackMap.get(mTabTags.get(position)); TabInfo info = tabStack.peek(); return Fragment.instantiate(mContext, info.clss.getName(), info.args); } @Override public void onTabChanged(String tabId) { int position = mTabHost.getCurrentTab(); mViewPager.setCurrentItem(position); } @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { } @Override public void onPageSelected(int position) { // Unfortunately when TabHost changes the current tab, it kindly // also takes care of putting focus on it when not in touch mode. // The jerk. // This hack tries to prevent this from pulling focus out of our // ViewPager. TabWidget widget = mTabHost.getTabWidget(); int oldFocusability = widget.getDescendantFocusability(); widget.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS); mTabHost.setCurrentTab(position); widget.setDescendantFocusability(oldFocusability); } @Override public void onPageScrollStateChanged(int state) { } } 

Add this for back button functionality in your MainActivity:

 @Override public void onBackPressed() { if (!mTabsAdapter.back(getSupportFragmentManager())) { super.onBackPressed(); } } 

If u like to save the Fragment State when it get’s removed. Let your Fragment implement the interface SaveStateBundle return in the function a bundle with your save state. Get the bundle after instantiation by this.getArguments() .

You can instantiate a tab like this:

 mTabsAdapter.addTab(mTabHost.newTabSpec("firstTabTag").setIndicator("First Tab Title"), FirstFragmentActivity.FirstFragmentFragment.class, null); 

works similiar if u want to add a Fragment on top of a Tab Stack. Important : I think, it won’t work if u want to have 2 instances of same class on top of two Tabs. I did this solution quick together, so I can only share it without providing any experience with it.

Replacing fragments in a viewpager is quite involved but is very possible and can look super slick. First, you need to let the viewpager itself handle the removing and adding of the fragments. What is happening is when you replace the fragment inside of SearchFragment, your viewpager retains its fragment views. So you end up with a blank page because the SearchFragment gets removed when you try to replace it.

The solution is to create a listener inside of your viewpager that will handle changes made outside of it so first add this code to the bottom of your adapter.

 public interface nextFragmentListener { public void fragment0Changed(String newFragmentIdentification); } 

Then you need to create a private class in your viewpager that becomes a listener for when you want to change your fragment. For example you could add something like this. Notice that it implements the interface that was just created. So whenever you call this method, it will run the code inside of the class below.

 private final class fragmentChangeListener implements nextFragmentListener { @Override public void fragment0Changed(String fragment) { //I will explain the purpose of fragment0 in a moment fragment0 = fragment; manager.beginTransaction().remove(fragAt0).commit(); switch (fragment){ case "searchFragment": fragAt0 = SearchFragment.newInstance(listener); break; case "searchResultFragment": fragAt0 = Fragment_Table.newInstance(listener); break; } notifyDataSetChanged(); } 

There are two main things to point out here:

  1. fragAt0 is a “flexible” fragment. It can take on whatever fragment type you give it. This allows it to become your best friend in changing the fragment at position 0 to the fragment you desire.
  2. Notice the listeners that are placed in the ‘newInstance(listener)constructor. These are how you will callfragment0Changed(String newFragmentIdentification)`. The following code shows how you create the listener inside of your fragment.

    static nextFragmentListener listenerSearch;

      public static Fragment_Journals newInstance(nextFragmentListener listener){ listenerSearch = listener; return new Fragment_Journals(); } 

You could call the change inside of your onPostExecute

 private class SearchAsyncTask extends AsyncTask{ protected Void doInBackground(Void... params){ . .//some more operation . } protected void onPostExecute(Void param){ listenerSearch.fragment0Changed("searchResultFragment"); } } 

This would trigger the code inside of your viewpager to switch your fragment at position zero fragAt0 to become a new searchResultFragment. There are two more small pieces you would need to add to the viewpager before it became functional.

One would be in the getItem override method of the viewpager.

 @Override public Fragment getItem(int index) { switch (index) { case 0: //this is where it will "remember" which fragment you have just selected. the key is to set a static String fragment at the top of your page that will hold the position that you had just selected. if(fragAt0 == null){ switch(fragment0){ case "searchFragment": fragAt0 = FragmentSearch.newInstance(listener); break; case "searchResultsFragment": fragAt0 = FragmentSearchResults.newInstance(listener); break; } } return fragAt0; case 1: // Games fragment activity return new CreateFragment(); } 

Now without this final piece you would still get a blank page. Kind of lame, but it is an essential part of the viewPager. You must override the getItemPosition method of the viewpager. Ordinarily this method will return POSITION_UNCHANGED which tells the viewpager to keep everything the same and so getItem will never get called to place the new fragment on the page. Here’s an example of something you could do

 public int getItemPosition(Object object) { //object is the current fragment displayed at position 0. if(object instanceof SearchFragment && fragAt0 instanceof SearchResultFragment){ return POSITION_NONE; //this condition is for when you press back }else if{(object instanceof SearchResultFragment && fragAt0 instanceof SearchFragment){ return POSITION_NONE; } return POSITION_UNCHANGED } 

Like I said, the code gets very involved, but you basically have to create a custom adapter for your situation. The things I mentioned will make it possible to change the fragment. It will likely take a long time to soak everything in so I would be patient, but it will all make sense. It is totally worth taking the time because it can make a really slick looking application.

Here’s the nugget for handling the back button. You put this inside your MainActivity

  public void onBackPressed() { if(mViewPager.getCurrentItem() == 0) { if(pagerAdapter.getItem(0) instanceof FragmentSearchResults){ ((Fragment_Table) pagerAdapter.getItem(0)).backPressed(); }else if (pagerAdapter.getItem(0) instanceof FragmentSearch) { finish(); } } 

You will need to create a method called backPressed() inside of FragmentSearchResults that calls fragment0changed. This in tandem with the code I showed before will handle pressing the back button. Good luck with your code to change the viewpager. It takes a lot of work, and as far as I have found, there aren’t any quick adaptations. Like I said, you are basically creating a custom viewpager adapter, and letting it handle all of the necessary changes using listeners

In your onCreateView method, container is actually a ViewPager instance.

So, just calling

 ViewPager vpViewPager = (ViewPager) container; vpViewPager.setCurrentItem(1); 

will change current fragment in your ViewPager .

Here’s my relatively simple solution to this problem. The keys to this solution are to use FragmentStatePagerAdapter instead of FragmentPagerAdapter as the former will remove unused fragments for you while the later still retains their instances. The second is the use of POSITION_NONE in getItem(). I’ve used a simple List to keep track of my fragments. My requirement was to replace the entire list of fragments at once with a new list, but the below could be easily modified to replace individual fragments:

 public class MyFragmentAdapter extends FragmentStatePagerAdapter { private List fragmentList = new ArrayList(); private List tabTitleList = new ArrayList(); public MyFragmentAdapter(FragmentManager fm) { super(fm); } public void addFragments(List fragments, List titles) { fragmentList.clear(); tabTitleList.clear(); fragmentList.addAll(fragments); tabTitleList.addAll(titles); notifyDataSetChanged(); } @Override public int getItemPosition(Object object) { if (fragmentList.contains(object)) { return POSITION_UNCHANGED; } return POSITION_NONE; } @Override public Fragment getItem(int item) { if (item >= fragmentList.size()) { return null; } return fragmentList.get(item); } @Override public int getCount() { return fragmentList.size(); } @Override public CharSequence getPageTitle(int position) { return tabTitleList.get(position); } } 

I doing something to similar to wize but in my answer yo can change between the two fragments whenever you want. And with the wize answer I have some problems when changing the orientation of the screen an things like that. This is the PagerAdapter looks like:

  public class MyAdapter extends FragmentPagerAdapter { static final int NUM_ITEMS = 2; private final FragmentManager mFragmentManager; private Fragment mFragmentAtPos0; private Map mFragmentTags; private boolean isNextFragment=false; public MyAdapter(FragmentManager fm) { super(fm); mFragmentManager = fm; mFragmentTags = new HashMap(); } @Override public Fragment getItem(int position) { if (position == 0) { if (isPager) { mFragmentAtPos0 = new FirstPageFragment(); } else { mFragmentAtPos0 = new NextFragment(); } return mFragmentAtPos0; } else return SecondPageFragment.newInstance(); } @Override public int getCount() { return NUM_ITEMS; } @Override public Object instantiateItem(ViewGroup container, int position) { Object obj = super.instantiateItem(container, position); if (obj instanceof Fragment) { // record the fragment tag here. Fragment f = (Fragment) obj; String tag = f.getTag(); mFragmentTags.put(position, tag); } return obj; } public void onChange(boolean isNextFragment) { if (mFragmentAtPos0 == null) mFragmentAtPos0 = getFragment(0); if (mFragmentAtPos0 != null) mFragmentManager.beginTransaction().remove(mFragmentAtPos0).commit(); if (!isNextFragment) { mFragmentAtFlashcards = new FirstPageFragment(); } else { mFragmentAtFlashcards = new NextFragment(); } notifyDataSetChanged(); } @Override public int getItemPosition(Object object) { if (object instanceof FirstPageFragment && mFragmentAtPos0 instanceof NextFragment) return POSITION_NONE; if (object instanceof NextFragment && mFragmentAtPos0 instanceof FirstPageFragment) return POSITION_NONE; return POSITION_UNCHANGED; } public Fragment getFragment(int position) { String tag = mFragmentTags.get(position); if (tag == null) return null; return mFragmentManager.findFragmentByTag(tag); } } 

The listener I implemented in the adapter container activity to put it to the fragment when attaching it, this is the activity:

  public class PagerContainerActivity extends AppCompatActivity implements ChangeFragmentListener { //... @Override public void onChange(boolean isNextFragment) { if (pagerAdapter != null) pagerAdapter.onChange(isNextFragment); } //... } 

Then in the fragment putting the listener when attach an calling it:

 public class FirstPageFragment extends Fragment{ private ChangeFragmentListener changeFragmentListener; //... @Override public void onAttach(Activity activity) { super.onAttach(activity); changeFragmentListener = ((PagerContainerActivity) activity); } @Override public void onDetach() { super.onDetach(); changeFragmentListener = null; } //... //in the on click to change the fragment changeFragmentListener.onChange(true); //... } 

And finally the listener:

 public interface changeFragmentListener { void onChange(boolean isNextFragment); } 

I followed the answers by @wize and @mdelolmo and I got the solution. Thanks Tons. But, I tuned these solutions a little bit to improve the memory consumption.

Problems I observed:

They save the instance of Fragment which is replaced. In my case, it is a Fragment which holds MapView and I thought its costly. So, I am maintaining the FragmentPagerPositionChanged (POSITION_NONE or POSITION_UNCHANGED) instead of Fragment itself.

Here is my implementation.

  public static class DemoCollectionPagerAdapter extends FragmentStatePagerAdapter { private SwitchFragListener mSwitchFragListener; private Switch mToggle; private int pagerAdapterPosChanged = POSITION_UNCHANGED; private static final int TOGGLE_ENABLE_POS = 2; public DemoCollectionPagerAdapter(FragmentManager fm, Switch toggle) { super(fm); mToggle = toggle; mSwitchFragListener = new SwitchFragListener(); mToggle.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { mSwitchFragListener.onSwitchToNextFragment(); } }); } @Override public Fragment getItem(int i) { switch (i) { case TOGGLE_ENABLE_POS: if(mToggle.isChecked()) { return TabReplaceFragment.getInstance(); }else { return DemoTab2Fragment.getInstance(i); } default: return DemoTabFragment.getInstance(i); } } @Override public int getCount() { return 5; } @Override public CharSequence getPageTitle(int position) { return "Tab " + (position + 1); } @Override public int getItemPosition(Object object) { // This check make sures getItem() is called only for the required Fragment if (object instanceof TabReplaceFragment || object instanceof DemoTab2Fragment) return pagerAdapterPosChanged; return POSITION_UNCHANGED; } /** * Switch fragments Interface implementation */ private final class SwitchFragListener implements SwitchFragInterface { SwitchFragListener() {} public void onSwitchToNextFragment() { pagerAdapterPosChanged = POSITION_NONE; notifyDataSetChanged(); } } /** * Interface to switch frags */ private interface SwitchFragInterface{ void onSwitchToNextFragment(); } } 

Demo link here.. https://youtu.be/l_62uhKkLyM

For demo purpose, used 2 fragments TabReplaceFragment and DemoTab2Fragment at position two. In all the other cases I’m using DemoTabFragment instances.

Explicación:

I’m passing Switch from Activity to the DemoCollectionPagerAdapter . Based on the state of this switch we will display correct fragment. When the switch check is changed, I’m calling the SwitchFragListener ‘s onSwitchToNextFragment method, where I’m changing the value of pagerAdapterPosChanged variable to POSITION_NONE . Check out more about POSITION_NONE . This will invalidate the getItem and I have logics to instantiate the right fragment over there. Sorry, if the explanation is a bit messy.

Once again big thanks to @wize and @mdelolmo for the original idea.

Espero que esto sea útil. 🙂

Let me know if this implementation has any flaws. That will be greatly helpful for my project.

I found simple solution, which works fine even if you want add new fragments in the middle or replace current fragment. In my solution you should override getItemId() which should return unique id for each fragment. Not position as by default.

There is it:

 public class DynamicPagerAdapter extends FragmentPagerAdapter { private ArrayList mPages = new ArrayList(); private ArrayList mFragments = new ArrayList(); public DynamicPagerAdapter(FragmentManager fm) { super(fm); } public void replacePage(int position, Page page) { mPages.set(position, page); notifyDataSetChanged(); } public void setPages(ArrayList pages) { mPages = pages; notifyDataSetChanged(); } @Override public Fragment getItem(int position) { if (mPages.get(position).mPageType == PageType.FIRST) { return FirstFragment.newInstance(mPages.get(position)); } else { return SecondFragment.newInstance(mPages.get(position)); } } @Override public int getCount() { return mPages.size(); } @Override public long getItemId(int position) { // return unique id return mPages.get(position).getId(); } @Override public Object instantiateItem(ViewGroup container, int position) { Fragment fragment = (Fragment) super.instantiateItem(container, position); while (mFragments.size() <= position) { mFragments.add(null); } mFragments.set(position, fragment); return fragment; } @Override public void destroyItem(ViewGroup container, int position, Object object) { super.destroyItem(container, position, object); mFragments.set(position, null); } @Override public int getItemPosition(Object object) { PagerFragment pagerFragment = (PagerFragment) object; Page page = pagerFragment.getPage(); int position = mFragments.indexOf(pagerFragment); if (page.equals(mPages.get(position))) { return POSITION_UNCHANGED; } else { return POSITION_NONE; } } } 

Notice: In this example FirstFragment and SecondFragment extends abstract class PageFragment, which has method getPage() .

after research i found solution with short code. first of all create a public instance on fragment and just remove your fragment on onSaveInstanceState if fragment not recreating on orientation change.

  @Override public void onSaveInstanceState(Bundle outState) { if (null != mCalFragment) { FragmentTransaction bt = getChildFragmentManager().beginTransaction(); bt.remove(mFragment); bt.commit(); } super.onSaveInstanceState(outState); } 

This is my way to achieve that.

First of all add Root_fragment inside viewPager tab in which you want to implement button click fragment event. Ejemplo;

 @Override public Fragment getItem(int position) { if(position==0) return RootTabFragment.newInstance(); else return SecondPagerFragment.newInstance(); } 

First of all, RootTabFragment should be include FragmentLayout for fragment change.

   

Then, inside RootTabFragment onCreateView , implement fragmentChange for your FirstPagerFragment

 getChildFragmentManager().beginTransaction().replace(R.id.root_frame, FirstPagerFragment.newInstance()).commit(); 

After that, implement onClick event for your button inside FirstPagerFragment and make fragment change like that again.

 getChildFragmentManager().beginTransaction().replace(R.id.root_frame, NextFragment.newInstance()).commit(); 

Hope this will help you guy.