El fragmento no se reemplaza sino que se coloca encima del anterior


104

Actividad:

FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();

Fragment1 fragment = new Fragment1();
Fragment2 fragment2 = new Fragment2();

transaction.replace(R.id.Fragment1, fragment);
transaction.addToBackStack(null);
transaction.commit();

FragmentTransaction transaction2 = getSupportFragmentManager().beginTransaction();
transaction2.replace(R.id.Fragment1, fragment2);
transaction2.addToBackStack(null);
transaction2.commit();

Código en la vista:

<fragment
    android:id="@+id/Fragment1"
    android:name="com.landa.fragment.Fragment1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentBottom="true"
    android:layout_alignParentLeft="true"
    android:layout_below="@+id/include1" /> 

El problema es que el contenido no se reemplaza realmente, se coloca en la parte superior (por lo que se superpone).

Cuando hago clic hacia atrás, el primer fragmento se muestra correctamente (sin el segundo), pero inicialmente ambos son visibles (quiero que solo el último sea visible).

¿Que me estoy perdiendo aqui?


En mi caso, el problema se debió al hecho de que no estaba usando la identificación apropiada de la vista del contenedor, es decir, no estaba pasando la correcta containerViewId(en el replacemétodo).
nbro

Respuestas:


145

Estás haciendo dos cosas mal aquí:

  1. No puede reemplazar un fragmento que está colocado estáticamente en un xmlarchivo de diseño. Debe crear un contenedor (por ejemplo, a FrameLayout) en el diseño y luego agregar el fragmento mediante programación usando FragmentTransaction.

  2. FragmentTransaction.replaceespera el id del contenedor que contiene el fragmento y no el id del fragmento como primer parámetro. Por lo tanto, debe pasar el primer argumento como la identificación del contenedor al que agregó el primer fragmento.

Puede consultar este enlace para obtener más detalles.


17
Usar FrameLayoutcomo recipiente es mejor que usar LinearLayout.
Marcel Bro

3
Usar un FrameLayout vacío en Activity también resolvió mi problema
Subtle Fox

1
Funciona haciendo esto. Pero luego, cuando inicio mi aplicación e inmediatamente presiono el botón Atrás, termino en un estado en el que el fragmento está vacío, en lugar de salir de la aplicación.
MasterScrat

@MasterScrat Omita el addTobackStack(..)al realizar su transacción por primera vez. Esto evitará colocar el contenedor FrameLayout vacío en la pila posterior. Aún podrá navegar de regreso al fragmento que agregó.
Alex Meuer

Aquí hay un gran video que demuestra su explicación. youtube.com/watch?v=EbcdMxAIr54
Estudiante de SQL y Java

32

Tuve un problema similar, pero mi problema fue que estaba usando dos administradores de Fragmentos diferentes: uno desde getSupportFragmentManager()y otro desde getFragmentManager(). Si agregué un fragmento con SupportFragmentManagery luego intenté reemplazar el fragmento con FragmentManager, el fragmento simplemente se agregaría en la parte superior. Necesitaba cambiar el código para que FragmentManagerse usara el mismo y eso solucionó el problema.


17

El sitio para desarrolladores de Android sugiere el uso de FrameLayoutpara cargar fragmentos dinámicamente en tiempo de ejecución. Ha codificado el fragmento en su archivo xml. Por lo tanto, no se puede eliminar en tiempo de ejecución como se menciona en este enlace:

http://developer.android.com/training/basics/fragments/creating.html

este enlace muestra cómo agregar fragmentos a través de su programa:

http://developer.android.com/training/basics/fragments/fragment-ui.html


7

Tuve el mismo problema y vi todas las respuestas, ¡pero ninguna de ellas contenía mi error! Antes de intentar reemplazar el fragmento actual, estaba mostrando el fragmento predeterminado en el xml de la actividad del contenedor de esta manera:

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

    <fragment
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:name="....ShopFragment"
        android:id="@+id/fragment"
        tools:layout="@layout/fragment_shop" />
</FrameLayout>

después de eso, aunque estaba pasando el FrameLayouta fragmentTransaction.replace()pero tuve el problema exacto. mostraba el segundo fragmento encima del anterior.

El problema se solucionó eliminando el fragmento del xml y mostrándolo programáticamente en el onCreate()método de la actividad del contenedor para la vista previa predeterminada al inicio del programa de esta manera:

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

y la actividad del contenedor xml:

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

4

Puede borrar backStack antes de reemplazar fragmentos:

    FragmentManager fm = getActivity().getSupportFragmentManager();

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

    // replace your fragments

el problema es que ha declarado el fragmento en su archivo de diseño xml. Por lo tanto, no se puede quitar / reemplazar en tiempo de ejecución.
Poonam Anthony

esto funcionó para mí, tratar de reemplazar un fragmento sin borrar el backstack parecía dejar la entrada de backstack más reciente sobre cualquier otro fragmento.
speedynomads

3
<FrameLayout
    android:id="@+id/fragment_frame_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="?android:windowBackground">
//Add fragment here
</FrameLayout>

Agregue android:background="?android:windowBackground">al recipiente en el que reside su fragmento. En mi caso, agregué un FrameLayout, eso debería ayudar.


1

Use un recipiente en lugar de usar un fragmento

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

Ahora en MainActivity

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

Tenga en cuenta que su clase de fragmento debe importar 'android.app.Fragment' Asegúrese de usar "support.v4" o las implementaciones "originales" y no las mezcle. Tenía este problema porque los había mezclado.


0

Estoy de acuerdo con la respuesta de Sapan Diwakar. Pero he encontrado una solución para hacer esto.

Primero, en su actividad (por ejemplo activity_main), donde tiene todos los diseños, agregue un FrameLayout. Su altura y anchura deberían ser match parent. Además, dale un id.

Ahora, en su fragmento que va a reemplazar el diseño actual, llame a onPause()y onResume(). Inicialice todos los contenedores internos en View. Y puesto su visibilitya GONEenonResume() y VISIBLEenonPause() .

NOTA : No es el FrameLayoutque está reemplazando con este fragmento.

Suponga que tiene ViewPager, TabLayout, ImageViewy una costumbre <fragment>en activity_main.xml. Agregue, FrameLayoutcomo se mencionó anteriormente.

En abcFragment.java, en onClick()función, poner addToBackstack(null)en transaction.

Código de ejemplo:

en xyzFragment, que va a reemplazar abcFragment (y todo lo que se muestra en activity_main.xml), haga esto

@Override
    public void onResume() {
        super.onResume();

    // On resume, make everything in activity_main invisible except this fragment.
    slidingTabs = getActivity().findViewById(R.id.sliding_tabs);
    viewPager = getActivity().findViewById(R.id.pager);
    miniPlayerFragment = getActivity().findViewById(R.id.mini_pager);

    slidingTabs.setVisibility(View.GONE);
    viewPager.setVisibility(View.GONE);
    miniPlayerFragment.setVisibility(View.GONE);
}

@Override
public void onPause() {
    super.onPause();

    // Make everything visible again
    slidingTabs = getActivity().findViewById(R.id.sliding_tabs);
    viewPager = getActivity().findViewById(R.id.pager);
    miniPlayerFragment = getActivity().findViewById(R.id.mini_pager);

    slidingTabs.setVisibility(View.VISIBLE);
    viewPager.setVisibility(View.VISIBLE);
    miniPlayerFragment.setVisibility(View.VISIBLE);
}

¡Feliz codificación!


0

Puede utilizar el método setTransition de FragmentTransaction para solucionar el problema de superposición.

transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);

0

En Oncreate ()

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

ahora este será siempre su fragmento predeterminado ... si agrega un fragmento en el diseño xml, siempre se superpondrá, así que configure el contenido inicial con el fragmento en el tiempo de ejecución


0

Tuve el mismo problema después de usar este problema resuelto

  1. Toma el diseño del marco donde estás reemplazando tu fragmento

    <FrameLayout
                    android:id="@+id/fragment_place"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent" />
  2. y código de reemplazo

    public void selectFrag(View view) {
    Fragment fr;
    
      if(view == findViewById(R.id.button2))
    {
         fr = new FragmentTwo();
    
     }else {
         fr = new FragmentOne();
     }
     FragmentManager fm = getFragmentManager();
     FragmentTransaction fragmentTransaction = fm.beginTransaction();
     fragmentTransaction.replace(R.id.fragment_place, fr);
     fragmentTransaction.commit();

si quieres un ejemplo completo te enviaré solo comentame ...


0

También tuve el mismo problema, pero fue porque no había cambiado el color de fondo del fragmento que estaba tratando de agregar a mi diseño de marcos.

Intente hacer esto, con layout_heighty layout_widthestablezca enmatch_parent


0

Una vez tuve este problema y descubrí que era porque había borrado accidentalmente el android:backgroundatributo que faltaba en su código xml. Creo que funciona como cuando estás pintando una pared, android:backgroundes el color que tendrá la pared y las otras vistas se colocan encima de ese color base. Cuando no pintes la pared antes de colocar tus vistas, estarán encima de lo que ya estaba en esa pared, en tu caso, tu otro fragmento. No sé si eso te ayudará, buena suerte.


0

He intentado sobre todo el caso e intento solucionar el problema, pero todavía no tengo una solución. No sé por qué no me funciona. Estoy de acuerdo con las respuestas anteriores porque muchos están de acuerdo.

Solo estoy extendiendo la respuesta y a continuación se muestra la forma en que me está funcionando.

He agregado esta propiedad android:clickable="true"en el diseño principal superior en el fragment.xmlarchivo.

Espero que alguien reciba ayuda.


0

Gracias a Sapan Diwakar y otros. Esta respuesta me ayudó. Simplemente creé un RelativeLayout sin un fragmento dentro de él, usé RelativeLayout como vista principal o de grupo, especifiqué esa vista de grupo en la transacción para reemplazar y funcionó.

Código:

getSupportFragmentManager().beginTransaction()
                            .replace(R.id.content_group_view, itemDetailFragment).commit();

XML:

 <RelativeLayout
         android:id="@+id/content_group_view"
         android:layout_width="match_parent"
         android:layout_height="match_parent">

 </RelativeLayout>

0

Verifique su ID de diseño de marco y reemplácelo como se muestra a continuación

fragmentTransactionChange = MainActivity.this.getSupportFragmentManager().beginTransaction();
fragmentTransactionChange.replace(R.id.progileframe, changeFragment);
fragmentTransactionChange.addToBackStack(null);
fragmentTransactionChange.commit();
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.