Estoy tratando de utilizar Fragmento con un ViewPager el uso de la FragmentPagerAdapter.
Lo que yo estoy buscando a lograr es que se reemplace un fragmento, posicionado en la primera página de la ViewPager, con otro.

El localizador se compone de dos páginas. La primera es la FirstPagerFragment, el segundo es el SecondPagerFragment. Al hacer clic en un botón de la primera página. Me gustaría cambiar el FirstPagerFragment con el NextFragment.

No es mi código de abajo.

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

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:padding="4dip"
android:gravity="center_horizontal"
android:layout_width="match_parent" android:layout_height="match_parent">
<android.support.v4.view.ViewPager
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1">
</android.support.v4.view.ViewPager>
</LinearLayout>

first.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/first_fragment_root_id"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button android:id="@+id/button"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:text="to next"/>
</LinearLayout>

Ahora el problema… que ID se debe utilizar en

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

?

Si puedo usar R.id.first_fragment_root_id, el reemplazo de las obras, sino de una Jerarquía Visor muestra un comportamiento extraño, como a continuación.

Al principio la situación es
Reemplazar el Fragmento dentro de un ViewPager

después de la sustitución de la situación es
Reemplazar el Fragmento dentro de un ViewPager

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

InformationsquelleAutor Noodles | 2011-10-11

18 Comentarios

  1. 154

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

    Me gustaría empezar por responder el autor de la pregunta sobre la que ID se debe utilizar; es el ID del contenedor, es decir, el ID de la vista localizador de sí mismo. Sin embargo, como usted probablemente ha notado usted mismo, utilizando el IDENTIFICADOR en el código hace que nada suceda. Voy a explicar por qué:

    Primero de todo, para hacer ViewPager la repoblación de las páginas, usted necesita llamar a notifyDataSetChanged() que reside en la base de la clase de su adaptador.

    Segundo, ViewPager utiliza el getItemPosition() método abstracto para comprobar qué páginas debe ser destruido, y que debe ser mantenido. La implementación por defecto de esta función siempre devuelve POSITION_UNCHANGED, que hace que ViewPager de mantener todas las páginas actuales, y, en consecuencia, no adjuntando tu nueva página. Por lo tanto, para hacer fragmento trabajo de reemplazo, getItemPosition() necesita ser reemplazado en el adaptador y debe devolver POSITION_NONE cuando se llama con un viejo, que se oculta, el fragmento como argumento.

    Esto también significa que el adaptador siempre debe ser consciente de que el fragmento que se debe mostrar en la posición 0, FirstPageFragment o NextFragment. Una forma de hacer esto es el suministro de un oyente a la hora de crear FirstPageFragment, que será llamado cuando es el momento para cambiar de fragmentos. Creo que esta es una buena cosa sin embargo, dejar que su fragmento adaptador de manejar todos fragmento de interruptores y las llamadas a ViewPager y FragmentManager.

    Tercero, FragmentPagerAdapter almacena en caché el utilizado fragmentos de un nombre que se deriva de la posición, entonces, si hay un fragmento en la posición 0, no será reemplazado aunque la clase es nueva. Hay dos soluciones, pero la más sencilla es usar el remove() función de FragmentTransaction, que se retire de su etiqueta.

    Que fue una gran cantidad de texto, aquí está el código que funcione en tu 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 alguien!

    • funciona para mí también, pero cómo implementar de nuevo el botón para mostrar el primer fragmento?
    • Gran explicación, pero podría publicar el código fuente completo de este, específicamente FirstPageFragment y SecondPageFragment clases.
    • Yo a mi me funciona así, pero no he sido capaz de revertir la acción, es decir, y creo que lo que @user1159819 significa que, una vez en NextFragment, usted podría querer volver a FirstFragment, no veo la manera de hacerlo con esta aplicación
    • Si u quiere un mayor enfoque modular, me ofreció una solución más sofisticada que se basa en wize las ideas.
    • Usted puede ver mi respuesta. Reemplaza los fragmentos y volver a primera.
    • Estoy teniendo problemas al intentar usar el tarjeta flip animación con esto. La animación no funciona con .remove(), sólo con replace(), pero el uso de replace se bloquea el programa, se sustituye fragmento de anima en el lugar correcto, pero nada anima en la que la sustituya, dejando un espacio en blanco negro de la página en la vista de buscapersonas. Pasando a otras páginas funciona, pero tan pronto como puedo regresar a la página negra de la aplicación se bloquea. Me pregunto si se debe anular aún más a los miembros de FragmentPagerAdapter?
    • Ah, y tengo que usar Support.V13.App.FragmentPagerAdapter como el adaptador, porque Support.V4.App.FragmentPagerAdapter no permitir que los nativos Fragments, sólo el apoyo de los fragmentos, y el apoyo de los fragmentos de bloqueo en objectAnimator animación que faltan.
    • ¿Cómo añadir el FirstPageFragmentListener a la agrupación en newInstance() ?
    • Ustedes podrían echar un vistazo a esta pregunta acerca de ViewPager? Gracias stackoverflow.com/questions/27937250/…
    • ¿qué mFragmentAtPos0 equiparar a?
    • Gracias – fue la simplicidad de aplicación, por el momento – que funcionó para mí.
    • Gracias, funcionó como un encanto. Una solución alternativa era cambiar a FragmentStatePagerAdapter pero por encima de solución funcionó con FragmentPagerAdapter
    • Se puede agregar el código donde puede manejar con FirstPageFragment.newInstance() escucha param?
    • Sé que esto es una vieja pregunta y la respuesta pero, ¿cómo se puede hacer esto en Xamarin android?
    • Por favor, ver a mi pregunta en stackoverflow.com/questions/39519889/…
    • Esto sólo funciona para mí si que me llame commitNow() en lugar de commit() al eliminar el fragmento. No sé por qué mi caso de uso es diferente, pero esperemos que esto va a salvar a alguien de algún tiempo.
    • en mi caso he tenido que cambiar de FragmentPagerAdapter a FragmentStatePagerAdapter y luego trabajar
    • ¿qué pasa si el fragmento es como NextFragment.newInstance(item:Item) que item se establece mediante un adaptador?

  2. 37

    De 13 de noviembre de 2012, repacing fragmentos en un ViewPager parece haberse convertido en mucho más fácil. Google lanzó Android 4.2 con soporte para anidada fragmentos, y también se apoyó en la nueva Android Support Library v11 así que esto vaya a funcionar en todo el camino de regreso a 1.6

    Es muy similar a la forma normal de la sustitución de un fragmento excepto que se usa la getChildFragmentManager. Parece que funciona, excepto la anidado fragmento backstack no apareció cuando el usuario hace clic en el botón atrás. Como por la solución en la que enlaza pregunta, usted necesita manualmente llamar a la popBackStackImmediate() en el niño el administrador del fragmento. Por lo que usted necesita para reemplazar onBackPressed() de la ViewPager actividad donde tendrás la actual fragmento de la ViewPager y llame a getChildFragmentManager().popBackStackImmediate() sobre él.

    Conseguir el Fragmento que se muestra actualmente es un poco chapucero así, he utilizado este sucio «android:switcher:VIEWPAGER_ID:ÍNDICE de» solución pero también se puede seguir la pista de todos los fragmentos de la ViewPager sí mismo, 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 de detalle se muestra en el ViewPager cuando el usuario hace clic en una fila, y con el botón de retroceso de trabajo. He intentado incluir sólo el código correspondiente para el bien de la brevedad, así que deje un comentario si quieres la versión completa de la aplicación subido a 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;
    }
    }
    }

    ListProductsFragment.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;
    }
    }
    • Será posible para que usted pueda subir el código a github? gracias.
    • plz, cargar este proyecto de ejemplo en github.
    • He intentado la solución, pero no se pudo obtener la convocatoria a getChildFragmentManager() para resolver. Estoy llamando desde un clic de escucha, similares a los de su código de ejemplo. El eclipse mensaje de error que dice «El método getChildFragmentManager() está definido por el tipo de MyFragment,» donde MyFragment se extiende desde SherlockFragment, al igual que de su ejemplo. Lo que me estoy perdiendo – alguna sugerencia?
    • He descargado de la API 17, Android 4.2, lo que me permitió empezar a usar getChildFragmentManager(). Pero me debe faltar algo de su solución, ya que estoy recibiendo ahora la superposición de edad + nuevos fragmentos en la pantalla. Nota: estoy tratando de usar la solución en concierto con el ejemplo de Google TabsAdapter código de developer.android.com/reference/android/support/v4/view/…. Gracias por todas las sugerencias y/o código de referencia.
    • Lo que hace R. id.products_list_linear referencia? Por favor, enlace a su código como se ofrecen.
    • la IDENTIFICACIÓN de las referencias externas fragmento de miembro. La clave para resolver este problema es el uso de anidado de los fragmentos (de esa manera usted no tiene que manipular viewpager adaptador).
    • TabPageIndicator mIndicator; ¿qué es esto? por favor, explique esto
    • Hay alguna forma de utilizar niño fragmentos de administrador con los nativos Fragments (en oposición a apoyar fragmentos)? Estoy usando Support.V13.App.FragmentPagerAdapter a feed nativo fragmentos ViewPager porque de lo contrario el tarjeta flip animación no es availbale.
    • ¿terminan resolviendo el problema que tenía? Estoy teniendo el mismo problema con la superposición de los viejos/nuevos fragmentos y me parece que no puede arreglarlo.
    • ¿Esto lo hace siempre a github?
    • georgiecasey tengo problemas con sus soluciones es el tipo de obras que, sin embargo, cuando el fragmets se sustituye el botón que reemplazar el fragmento es todavía visible en la pantalla. Sabes por casualidad como puedo quitarlo

  3. 32

    Basa en @wize ‘s respuesta, que he encontrado muy útil y elegante, pude lograr lo que quería parcialmente, porque yo quería que el cability para volver a la primera Fragmento de una vez reemplazado. He logrado poco 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 realizar la sustitución, basta con definir un campo estático, del tipo CalendarPageFragmentListener y se inicializan a través de la newInstance métodos de los correspondientes fragmentos y llame a FirstFragment.pageListener.onSwitchToNextFragment() o NextFragment.pageListener.onSwitchToNextFragment() respictevely.

    • ¿Cómo se puede realizar el reemplazo? no es posible inicializar el Oyente sin reemplazar el onSwitchToNext método.
    • no u perder el estado guardado en mFragmentAtPos0 si u gire el dispositivo?
    • Yo en realidad mejor esta solución con el fin de ahorrar mFragmentAtPos0 referencia a la hora de guardar el estado de actividad. No es la solución más elegante, pero funciona.
    • Usted puede ver mi respuesta. Reemplaza los fragmentos y volver a primera.
    • Podría usted echa un vistazo a esta pregunta acerca de ViewPager? Gracias stackoverflow.com/questions/27937250/…
    • Hacer que realmente necesitamos para mantener el Fragmento instancia mFragmentAtPos0? En su lugar podemos guardar sólo el POSTION_NONE o POSITION_UNCHANGED, la cual notificará a la adaptador. Podemos mostrar lo que nunca fragmento necesitamos en getItem. Mis pensamientos.. Alguna sugerencia? Cualquier agujeros de bucle en la implementación de esta manera?

  4. 21

    He implementado una solución para:

    • Dinámica fragmento de reemplazo dentro de la pestaña
    • Mantenimiento de la historia por ficha
    • De trabajo con cambios de orientación de la

    Los trucos para conseguir esto son los siguientes:

    • Utilizar el notifyDataSetChanged() método para aplicar el fragmento de reemplazo
    • Usar el fragmento de administrador sólo para la parte trasera del escenario y no para fragament reemplazo
    • Mantener la historia utilizando el patrón memento (pila)

    El adaptador de código es la 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<TabInfo> mTabs = new LinkedList<TabInfo>();
    /** The total number of tabs. */
    private int TOTAL_TABS;
    private Map<Integer, Stack<TabInfo>> history = new HashMap<Integer, Stack<TabInfo>>();
    /**
    * 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<TabInfo> 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<TabInfo>());
    }
    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 añadir todas las pestañas, tenemos que llamar al método createHistory(), para crear la inicial de la historia

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

    Cada vez que desea reemplazar un fragmento de una pestaña específica de llamar:
    reemplazar final(int posición, final de la Clase 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 de atrás presionado usted necesita llamar a la espalda() método:

    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 sherlock de la barra de acción y con gesto de barrido.

    • es genial! podrías ponerlo en el github?
    • Esta aplicación es el más limpio de todos los que aquí, y las direcciones de cada tema. Debe ser aceptado respuesta.
    • ¿Alguien tiene problemas con esta aplicación? Tengo 2 de ellos. 1. la primera vuelta no se registra – tengo que hacer clic en atrás dos veces para que se registre. 2. Después de hacer clic en atrás (dos veces) en una ficha y me vaya a la ficha b, cuando voy de regreso a la ficha de un solo muestra el contenido de la ficha b
  5. 7

    tl;dr: Usar un host fragmento que es responsable de la sustitución de su contenido alojado y sigue la pista de un nuevo historial de navegación (como en un navegador).

    Como el caso de uso consiste en una cantidad fija de pestañas mi solución funciona bien: La idea es llenar el ViewPager con las instancias de una clase personalizada HostFragment, que es capaz de reemplazar su contenido alojado y mantiene su propio historial de navegación. Para reemplazar la alojado fragmento que hacer 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();
    }
    }

    Todos que el método no es para reemplazar el marco de diseño con el id R.id.hosted_fragment con el fragmento proporcionado para el método.

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

    • Genial, esto funciona para mí
    • Aunque esto parece más torpe, creo que es en realidad la mejor (en términos de estructura y facilidad de mantenimiento) manera de hacer esto.
    • Me acaban de headbutting un NPE. :/ No se puede encontrar el punto de Vista de que va a ser reemplazado
  6. 6

    Algunos de los presentados en soluciones me han ayudado mucho a resolver parcialmente el problema, pero todavía hay una cosa importante que falta en las soluciones que ha producido excepciones inesperadas y negro contenido de la página en lugar de un fragmento de contenido en algunos casos.

    La cosa es que FragmentPagerAdapter clase es el uso de ID de elemento para almacenar en caché los fragmentos FragmentManager. Por esta razón, usted necesita para reemplazar también el getItemId(int posición) método que devuelve el correo. g. posición para el nivel superior de las páginas y 100 + posición para páginas de detalles. De lo contrario, el creado anteriormente de nivel superior fragmento sería devuelto desde la caché en lugar de detalle a nivel de fragmento.

    Además, voy a compartir aquí un ejemplo completo de cómo aplicar pestañas como actividad con Fragmento páginas con ViewPager y botones de la ficha de usar RadioGroup que permite la sustitución de los de nivel superior de las páginas con la información detallada de las páginas y también es compatible con botón atrás. Esta aplicación es compatible con un solo nivel de la espalda de apilamiento (elemento elemento de lista de detalles), pero multi-nivel de apilamiento de implementación es sencilla. Este ejemplo funciona muy bien en casos normales, excepto de que es tirar un NullPointerException en caso de que cuando se cambia a e. g. segunda página, cambiar el fragmento de la primera página (aunque no visible) y volver a la primera página. Voy a publicar una solución a este problema de una vez voy a averiguar:

    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<Fragment>(){};
    mBackFragments = new ArrayList<Fragment>(){};
    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<Fragment> mFragments;
    /**
    * List of page fragments to return to in onBack();
    */
    private List<Fragment> mBackFragments;
    }
    /**
    * Tab fragments adapter.
    */
    private PagerAdapter mPagerAdapter;
    }
    • Hmm, hay otro problema con este código. Cuando quiero iniciar una actividad a partir de un fragmento que se ha eliminado y añadido aggain, me sale un error: «Error de ahorro de estado: activo NewFirstFragment{405478a0} ha despejado index: -1» (completo seguimiento de la pila: nopaste.info/547a23dfea.html). Mirando hacia el android fuentes, me imagino que tiene algo que ver con backstack pero no sé cómo solucionarlo hasta ahora. ¿Alguien tiene una idea?
    • Fresco, utilizando <code>mFragmentManager.beginTransaction().detach(old_fragment).attach(fragment).commit();</code&gt y, en lugar de <pre>mFragmentManager.beginTransaction().setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN).remove(old_fragment).add(mContainer.getId(), fragmento).commit();< pre> en el ejemplo de arriba se parece a solucionar los dos problemas :-).
    • Si utiliza este método, asegúrese de no dejar que Android recrear su Actividad cuando se gire el dispositivo. De lo contrario, el PagerAdapter va a ser re-creado y usted perderá su mBackFragments. Esto también va en serio confundir la FragmentManager. El uso de la BackStack evita este problema, a expensas de una forma más complicada la aplicación de PagerAdapter (es decir, no se puede heredar de FragmentPagerAdapter.)
  7. 6

    He creado un ViewPager con 3 elementos y 2 sub elementos de índice 2 y 3, y aquí lo que yo quería hacer..

    Reemplazar el Fragmento dentro de un ViewPager

    Me han puesto en práctica con la ayuda de las preguntas anteriores y las respuestas de StackOverFlow y aquí está el enlace.

    ViewPagerChildFragments

    • Su proyecto falla, si se gira el dispositivo.
  8. 6

    Para reemplazar un fragmento dentro de un ViewPager puede mover los códigos fuente de ViewPager, PagerAdapter y FragmentStatePagerAdapter clases en el proyecto y añadir el siguiente código.

    en ViewPager:

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

    en 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() garantiza que después de la próxima convocatoria de getItem() volver newFragment
    getFragmentPosition() devuelve la posición del fragmento en el adaptador.

    Ahora, para reemplazar fragmentos de la llamada

    mAdapter.replaceFragmetns(mViewPager, oldFragment, newFragment);

    Si estás interesado en un proyecto de ejemplo que se me pregunta por las fuentes.

    • ¿Cómo deben los métodos getFragmentPosition() y handleGetItemInbalidated() ser como? Soy incapaz de actualizar getItem() para devolver NewFragment.. por Favor ayuda..
    • puedes compartir tu la fuente de ejemplo,muy gracias
    • Hola! Por favor, encontrar el proyecto de prueba en este enlace files.mail.ru/eng?back=%2FEZU6G4
    • El proyecto de prueba falla, si u gire el dispositivo.
    • el enlace parece caducado.Se puede por favor compartir el código
    • Usted puede ver mi respuesta. Reemplaza los fragmentos y volver a primera.

  9. 4

    Funciona muy bien con los AndroidTeam la solución, sin embargo, me di cuenta de que tenía la capacidad de ir mucho como FrgmentTransaction.addToBackStack(null) Pero la simple adición de esto sólo hará que el Fragmento a ser reemplazado sin necesidad de notificar el ViewPager. La combinación de la solución aportada con esta leve mejora le permite volver a su estado anterior, por el mero hecho primordial de la actividad onBackPressed() método. El mayor inconveniente es que sólo volver en un tiempo que puede resultar en varios clics

    private ArrayList<Fragment> bFragments = new ArrayList<Fragment>();
    private ArrayList<Integer> bPosition = new ArrayList<Integer>();
    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.

    También en cuanto a las getFragmentPosition() va es bastante getItem() a la inversa. Usted sabe que los fragmentos de ir a dónde, sólo asegúrese de que usted regrese a la posición correcta será en. He aquí un ejemplo:

        @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;
    }
  10. 2

    También me hicieron una solución, que está trabajando con Pilas. Es más modular enfoque por lo que u no tiene que especificar cada uno de los fragmentos de Detalle y el Fragmento en su FragmentPagerAdapter. Es construir en la parte superior de la Ejemplo de ActionbarSherlock que deriva si estoy en lo correcto desde el Google Demo de la Aplicación.

    /**
    * 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<String> mTabTags = new ArrayList<String>();
    private HashMap<String, Stack<TabInfo>> mTabStackMap = new HashMap<String, Stack<TabInfo>>();
    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<TabInfo> tabStack = new Stack<TabInfo>();
    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<TabInfo> 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<TabInfo> 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<Class<?>> positionNoneHack = new ArrayList<Class<?>>();
    for(Stack<TabInfo> 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<TabInfo> 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) {
    }
    }

    Agregar esto para botón atrás la funcionalidad en el MainActivity:

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

    Si te gusta guardar el Fragmento Estado cuando es eliminado. Deje que su Fragmento de implementar la interfaz SaveStateBundle de retorno de la función de un paquete con su estado de ahorro. Obtener el paquete después de la creación de instancias por this.getArguments().

    Puede crear instancias de una ficha como esta:

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

    obras similares si u desea agregar un Fragmento en la parte superior de una Ficha de la Pila.
    Importante: yo creo que no va a funcionar si u quiere tener 2 instancias de la misma clase en la parte superior de dos Pestañas.
    Hice esta solución rápida juntos, así que sólo puedo compartir sin necesidad de proporcionar ninguna experiencia con ella.

    • Tengo un nullpointer excepción al pulsar el botón atrás y mi reemplazado fragmento no es visible. Así que tal vez estoy haciendo algo mal: ¿cuál debería ser la llamada correcta a cambio fragmentos correctamente?
    • Actualización: tengo la mayor parte de las cosas fijas, sin embargo, si presiono un botón atrás después de la adición de un nuevo fragmento y, a continuación, vaya a la otra pestaña y la espalda, tengo un nullpointer excepción. Así que tengo 2 preguntas: 1: ¿cómo puedo eliminar el historial de una ficha y asegurarse de que sólo el último fragmento (parte superior de la te de la pila) es todavía presente? 2: ¿cómo puedo deshacerme de la nullpointer excepción?
    • 1: u puede conseguir la derecha de la pila de mTabStackMap y, a continuación, quite todos los TabInfo objeto que se encuentra en la parte superior de la pila, 2: muy difícil de decir, hacer una pregunta con el stacktrace entonces yo podría tratar de averiguar, estas seguro que no es un error en el código? Esto sucede también si u cambiar a una ficha (y luego de vuelta) que se encuentra en la vecindad directa (derecha o izquierda)?
    • ¿Tienes un ejemplo completo del proyecto para esto? gracias
    • Ok, me encontré con un nuevo problema: si yo gire mi pantalla, a continuación, la pila parece estar vacía de nuevo? Parece que perder la pista de los elementos anteriores…
    • sí me encontré con el mismo problema, pero se lo esperaba, la actividad se presenta recreado si u gire el dispositivo esto significa que su antiguo variables están recibiendo comió por la GB, la solución sería guardar las pilas y tabinfos en el savestatebundle en el método onDestroy y, a continuación, recuperar la tabsadapter estado en recreaciones de la actividad. Va a hacer un poco de tiempo, pero cajero automático que hay mucho que hacer en otras cosas. También hay un rápido sucio corrección para rotar el dispositivo de google tiene que ver con el archivo de manifiesto.
    • no atm.
    • gracias. Yo estaba usando este código pero anidado fragmentos son ahora posibles de modo que ya no es un problema. 🙂
    • Yo estoy usando ese hack, pero esto va a empeorar cuando la actividad ha permanecido alrededor por mucho tiempo. Supongo que mantener la tabstacks y tabinfo es el camino a seguir.
    • Si me gustaría hacer a mí mismo, entonces sería sabio para proporcionar obtener’ers y establecer’ers de la tabstacks y tabinfo en el tabsadapter y dejar que el mainactivity guardar el estado en onPause y re-inicializar el adaptador en onResume?
    • Estoy parado en un problema cuando quiero entrar a su estructura jsonified ;-), puede proporcionar una respuesta a stackoverflow.com/questions/13460200/… para mí?
    • parece ya resuelto. Siéntase libre de preguntar si usted tiene otros problemas.

  11. 2

    Sustitución de fragmentos en un viewpager es bastante complicado, pero es muy posible y se puede ver super slick. En primer lugar, usted debe dejar que el viewpager sí mismo manejar la extracción y la adición de los fragmentos. Lo que sucede es que cuando vuelva a colocar el fragmento dentro de SearchFragment, su viewpager conserva su fragmento de vistas. Así que al final termina con una página en blanco porque el SearchFragment se elimina cuando se trate de reemplazarlo.

    La solución es crear un oyente dentro de su viewpager que va a manejar los cambios realizados fuera de ella así que primero agregar este código a la parte inferior de su adaptador.

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

    Entonces usted necesita para crear una clase privada en su viewpager que se convierte en un agente de escucha para cuando desea cambiar su fragmento. Por ejemplo, se puede añadir algo como esto. Aviso que implementa la interfaz que se acaba de crear. Así que cuando usted llama a este método, se ejecuta el código dentro de la clase de abajo.

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

    Hay dos cosas principales que señalar aquí:

    1. fragAt0 es un «flexible» fragmento. Se puede tomar en cualquier tipo de fragmento que darle. Esto permite que se convierta en tu mejor amigo en cambio el fragmento en la posición 0 para el fragmento que deseo.
    2. Aviso a los oyentes que se colocan en el ‘newInstance(el que escucha)constructor. Estos son la forma en que se callfragment0Changed(Cadena newFragmentIdentification)`. El código siguiente muestra cómo crear la escucha en el interior de su fragmento.

      estática nextFragmentListener listenerSearch;

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

    Se podría llamar el cambio en el interior de su onPostExecute

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

    Esto desencadenaría el código dentro de su viewpager para cambiar su fragmento en la posición cero fragAt0 a convertirse en un nuevo searchResultFragment. Hay dos más pequeñas piezas que usted necesita para añadir a la viewpager antes de que se convirtiera funcional.

    Uno estaría en la getItem reemplazar el método de la 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();
    }

    Ahora sin esta pieza final que aún así consigue una página en blanco. Tipo de cojo, pero es una parte esencial de la viewPager. Se debe reemplazar la getItemPosition método de la viewpager. Normalmente este método devolverá POSITION_UNCHANGED que dice el viewpager de mantener todo igual y así getItem nunca será llamado para colocar el nuevo fragmento en la página. He aquí un ejemplo de algo que podría hacer

    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
    }

    Como he dicho, el código se pone muy complicado, pero básicamente tienes que crear un adaptador personalizado para su situación. Las cosas que he mencionado, será posible cambiar el fragmento. Le va a tomar un largo tiempo para disfrutar de todo, así que sería paciente, pero tendrá sentido. Es totalmente vale la pena tomarse el tiempo, ya que puede hacer realmente una mancha en busca de la aplicación.

    Aquí está la pepita para el manejo del botón atrás. Pon esto en el interior de su 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();
    }
    }

    Usted tendrá que crear un método llamado backPressed() dentro de FragmentSearchResults que llama fragment0changed. Esta en tándem con el código que mostré antes manejará pulsando el botón back. Buena suerte con tu código para cambiar el viewpager. Se necesita un montón de trabajo, y lo que he encontrado, no hay ninguna rápido adaptaciones. Como he dicho, que son, básicamente, la creación de una costumbre viewpager adaptador, y dejar que se hace cargo de todos los cambios necesarios utilización de detectores

    • Gracias por esta solución. Pero, ¿has tenido algún problema después de la rotación de pantalla. Mi aplicación se bloquea cuando me gire la pantalla y tratando de volver a cargar otro fragmento de la misma ficha.
    • Ha sido un tiempo desde que he hecho Android dev, pero mi conjetura es que no es una pieza de datos que ya no existe su aplicación está contando. Al girar, la totalidad de la actividad se reinicia y puede causar accidentes si intenta volver a cargar su estado anterior sin todos los datos que necesita (es decir desde el paquete en el onPause, onResume)
  12. 2

    En su onCreateView método, container es en realidad un ViewPager instancia.

    Así, simplemente llamando a la

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

    voluntad de cambio actual del fragmento en su ViewPager.

    • De horas de búsqueda, fue esta una línea de código que necesitaba para hacer todas mis fichas funcionan correctamente. vpViewPager.setCurrentItem(1);. Me fui a través de cada una de las personas ejemplo, no pasa nada cada vez hasta que finalmente llegué a la suya. Gracias.
    • la mente de soplado… esto es increíble!! No me di cuenta de que el contenedor variable fue el viewpager sí mismo. Esta respuesta ha de ser explorado primero antes que todos los otros largos queridos. Además, no hay ningún pasando de escucha de las variables para el fragmento constructor que simplifica toda la aplicación al Android auto-recrea fragmentos usando la opción predeterminada no-arg constructor cuando config cambios.
    • no es esto acaba de cambiar a una ficha existente? cómo se relaciona con la sustitución de fragmentos?
    • De acuerdo con @behelit, esto no responde a la pregunta, se acaba de mover el ViewPager a otra página, no reemplazar cualquier fragmento.
  13. 1

    Aquí está mi solución relativamente simple a este problema. La clave de esta solución es usar FragmentStatePagerAdapter en lugar de FragmentPagerAdapter como el primero será quitar sin utilizar fragmentos para usted, mientras que el segundo aún conserva sus instancias. El segundo es el uso de POSITION_NONE en getItem(). He utilizado una simple Lista para hacer un seguimiento de mis fragmentos. Mi necesidad era reemplazar la lista completa de los fragmentos a la vez con una nueva lista, pero el siguiente podría ser fácilmente modificado para reemplazar fragmentos individuales:

    public class MyFragmentAdapter extends FragmentStatePagerAdapter {
    private List<Fragment> fragmentList = new ArrayList<Fragment>();
    private List<String> tabTitleList = new ArrayList<String>();
    public MyFragmentAdapter(FragmentManager fm) {
    super(fm);
    }
    public void addFragments(List<Fragment> fragments, List<String> 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);
    }
    }
  14. 1

    He encontrado solución simple, que funciona bien, incluso si desea agregar nuevos fragmentos en el medio o reemplazar los actuales fragmento. En mi solución debe reemplazar getItemId() que debe devolver identificador único para cada fragmento. No por su posición como por defecto.

    Hay que:

    public class DynamicPagerAdapter extends FragmentPagerAdapter {
    private ArrayList<Page> mPages = new ArrayList<Page>();
    private ArrayList<Fragment> mFragments = new ArrayList<Fragment>();
    public DynamicPagerAdapter(FragmentManager fm) {
    super(fm);
    }
    public void replacePage(int position, Page page) {
    mPages.set(position, page);
    notifyDataSetChanged();
    }
    public void setPages(ArrayList<Page> 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;
    }
    }
    }

    Aviso: En este ejemplo FirstFragment y SecondFragment se extiende clase abstracta PageFragment, que tiene el método de getPage().

  15. 1

    Estoy haciendo algo similar a wize pero en mi respuesta yo puede cambiar entre los dos fragmentos siempre que lo desee. Y con el wize respuesta tengo algunos problemas cuando se cambia la orientación de la pantalla y cosas así. Este es el PagerAdapter parece:

        public class MyAdapter extends FragmentPagerAdapter
    {
    static final int NUM_ITEMS = 2;
    private final FragmentManager mFragmentManager;
    private Fragment mFragmentAtPos0;
    private Map<Integer, String> mFragmentTags;
    private boolean isNextFragment=false;
    public MyAdapter(FragmentManager fm)
    {
    super(fm);
    mFragmentManager = fm;
    mFragmentTags = new HashMap<Integer, String>();
    }
    @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);
    }
    }

    El oyente que he implementado en el adaptador de contenedor de actividad para poner a el fragmento al conectar, esta es la actividad:

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

    A continuación, en el fragmento poniendo al oyente cuando se conecte una llamada de él:

    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);
    //...
    }

    Y, finalmente, el oyente:

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

    He seguido las respuestas por @wize y @mdelolmo y me dieron la solución. Gracias Toneladas. Pero, en sintonía con estas soluciones un poco para mejorar el consumo de memoria.

    Problemas que he observado:

    Que guarda la instancia de Fragment que se sustituye. En mi caso, es un Fragmento que contiene MapView y pensé que su costoso. Así que, yo soy el mantenimiento de la FragmentPagerPositionChanged (POSITION_NONE or POSITION_UNCHANGED) en lugar de Fragment sí mismo.

    Aquí está mi aplicación.

      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 enlace aquí.. https://youtu.be/l_62uhKkLyM

    Para efectos de demostración, se utiliza 2 fragmentos de TabReplaceFragment y DemoTab2Fragment en la posición dos. En todos los otros casos que estoy usando DemoTabFragment instancias.

    Explicación:

    Estoy pasando Switch de la Actividad de la DemoCollectionPagerAdapter. Sobre la base del estado de este interruptor vamos a mostrar correcta fragmento. Cuando el interruptor de verificación es cambiado, estoy llamando a la SwitchFragListener‘s onSwitchToNextFragment método, donde estoy cambiando el valor de pagerAdapterPosChanged variable POSITION_NONE. Ver más sobre POSITION_NONE. Esto invalidará la getItem y he lógicas para instanciar el derecho fragmento de allí. Lo siento, si la explicación es un poco desordenado.

    Una vez más muchas gracias a @wize y @mdelolmo de la idea original.

    Espero que esto sea útil. 🙂

    Quiero saber si esta aplicación tiene ningún defecto. Que será de gran ayuda para mi proyecto.

  17. 0

    después de la investigación, he encontrado la solución con un código corto.
    en primer lugar, crear una instancia pública de los fragmentos y acaba de quitar su fragmento en onSaveInstanceState si el fragmento no se recrea en el cambio de orientación.

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

    Esta es mi manera de lograr eso.

    Primero de todo, agregar Root_fragment dentro de viewPager la pestaña en la que desea implementar haga clic con el botón fragment evento. Ejemplo;

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

    Primero de todo, RootTabFragment debe incluir FragmentLayout para fragmentar el cambio.

    <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/root_frame"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    </FrameLayout>

    Entonces, dentro de RootTabFragment onCreateView, implementar fragmentChange para su FirstPagerFragment

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

    Después de eso, implementar onClick evento para tu botón en el interior de FirstPagerFragment y hacer fragmento de cambio como eso otra vez.

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

    Espero que esto le ayudará chico.

Dejar respuesta

Please enter your comment!
Please enter your name here