2012-06-02 23 views
162

decir que tengo una actividad que tiene fragmentos añadidos mediante programación:mediante programación volver al fragmento anterior en el backstack

private void animateToFragment(Fragment newFragment, String tag) { 
    FragmentTransaction ft = getFragmentManager().beginTransaction(); 
    ft.replace(R.id.fragment_container, newFragment, tag); 
    ft.addToBackStack(null); 
    ft.commit(); 
} 

¿Cuál es la mejor manera de volver al fragmento anterior, que era visible?

He encontrado Trigger back-button functionality on button click in Android pero estoy pensando en la simulación de un evento de tecla de retroceso no es la manera correcta de hacerlo (y no puedo conseguir que funcione bien):

dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK)); 

Llamada simplemente finish() Cierra la actividad que no me interesa.

¿Hay una mejor manera de hacerlo?

Respuesta

265

vistazo a los métodos getFragmentManager().popBackStack() (hay varios para elegir)

http://developer.android.com/reference/android/app/FragmentManager.html#popBackStack()

+71

'getFragmentManager(). PopBackStackImmediate();' hizo el truco. Gracias. –

+0

Sin embargo, ¿dónde pondría este método? En mi pestaña oyente? – rasen58

+1

sin ver el código, es difícil de decir ... pero debe ir en la sección del código que se ejecuta cuando desea "cerrar" el fragmento actual y volver al fragmento anterior. – stuckless

105

dar más detalles sobre las otras respuestas proporcionadas, esto es mi solución (colocado en una actividad):

@Override 
public void onBackPressed(){ 
    FragmentManager fm = getFragmentManager(); 
    if (fm.getBackStackEntryCount() > 0) { 
     Log.i("MainActivity", "popping backstack"); 
     fm.popBackStack(); 
    } else { 
     Log.i("MainActivity", "nothing on backstack, calling super"); 
     super.onBackPressed(); 
    } 
} 
+5

y por qué está sucediendo eso. En el ejemplo de fragmentación http://developer.android.com/training/basics/fragments/index.html, no están superando el evento de repliegue y, sin embargo, pueden volver a apilar el fragmento. He usado \t trasaction.addToBackStack (null); pero nada pasa. ¿Puedes explicar por qué? –

+0

@MurtazaHussain probablemente debería hacer una nueva pregunta si quiere ayuda con esto. Es un poco difícil ver lo que está pasando sin mirar más código. –

+2

En mi caso, tuve que hacer 'fm.getBackStackEntryCount()> 1' para llamar a la actividad cuando solo hay el primer fragmento en la pila. –

21

Cuando estamos actualizando/agregamos los fragmentos,

Debe Incluir el .addToBackStack().

getSupportFragmentManager().beginTransaction() 
    .add(detailFragment, "detail") // Add this transaction to the back stack (name is an optional name for this back stack state, or null). 
    .addToBackStack(null) 
    .commit(); 

Después de que si damos la getFragments.popBackStackImmediate() devolverá true si añadimos/actualizar los fragmentos, y volver a la pantalla actual.

1

Vuelve programáticamente al fragmento anterior utilizando el siguiente código.

if (getFragmentManager().getBackStackEntryCount() > 0) 
{ 
      getFragmentManager().popBackStack(); 
      return; 
} 
super.onBackPressed(); 
15

replace() hace 2 cosas:

  1. Retire fragmento añadido actualmente (A) desde el contenedor (C) que se indica
  2. Añadir nuevo fragmento (B) al mismo recipiente

Estas 2 operaciones son lo que se guarda como un registro/transacción Backstack. Tenga en cuenta que el fragmento A permanece en estado created, y su vista se destruye.

Ahora popBackStack() invierte su última transacción que ha agregado a BackStack.

En este caso sería de 2 pasos:

  1. Quitar B de C
  2. Añadir A a C

Después de esto, el fragmento B se convierte en detached, y si no impidió referencias a él, será basura recolectada.

Para responder la primera parte de su pregunta, no hay llamada onCreate(), porque FragmentB se mantuvo en el estado created. Y la respuesta a la segunda parte de la pregunta es un poco más larga.

En primer lugar, es importante comprender que en realidad no agrega Fragments a Backstack, añada FragmentTransactions. Entonces, cuando piensas que "reemplazas con el Fragmento B, agregando el Fragmento A a la pila posterior", realmente agregas toda esta operación a la retroinstalación, es decir reemplazo de A con B. Este reemplazo consta de 2 acciones: eliminar A y B. agregue B.

Luego, el siguiente paso es el estallido de la transacción que contiene este reemplazo. Entonces, no estás reventando FragmentA, estás invirtiendo "remove A, add B", que se revirtió es "remove B, add A".

Y luego paso final debería ser más claro - no hay B que FragmentManager es consciente de, por lo que cuando se agrega mediante la sustitución de A con B en su última etapa, B tiene que ir a través de sus primeros métodos de ciclo de vida - onAttach() y onCreate().

El siguiente código ilustra lo que está sucediendo.

FragmentManager fm = getFragmentManager(); 
FragmentA fragmentA = new FragmentA(); 
FragmentB fragmentB = new FragmentB(); 

// 1. Show A 
fm.beginTransaction() 
    .add(fragmentA, R.id.container) 
    .commit(); 

// 2. Replace A with B 
// FragmentManager keeps reference to fragmentA; 
// it stays attached and created; fragmentB goes 
// through lifecycle methods onAttach(), onCreate() 
// and so on. 
fm.beginTransaction() 
    .replace(fragmentB, R.id.container) 
    .addToBackstack(null) 
    .commit(); 

// 2'. Alternative to replace() method 
fm.beginTransaction() 
    .remove(fragmentA) 
    .add(fragmentB, R.id.container) 
    .addToBackstack(null) 
    .commit(); 

// 3. Reverse (2); Result - A is visible 
// What happens: 
// 1) fragmentB is removed from container, it is detached now; 
//  FragmentManager doesn't keep reference to it anymore 
// 2) Instance of FragmentA is placed back in the container 
// Now your Backstack is empty, FragmentManager is aware only 
// of FragmentA instance 
fm.popBackStack(); 

// 4. Show B 
// Since fragmentB was detached, it goes through its early 
// lifecycle methods: onAttach() and onCreate(). 
fm.beginTransaction() 
    .replace(fragmentB, R.id.container) 
    .addToBackstack(null) 
    .commit(); 
3

Agregue esas líneas a su método onBackPressed(). popBackStackImmediate() método le devolverá al fragmento anterior si usted tiene cualquier fragmento en la pila de vuelta `

if(getFragmentManager().getBackStackEntryCount() > 0){ 
    getFragmentManager().popBackStackImmediate(); 
} 
else{ 
    super.onBackPressed(); 
} 

`

0

Esta solución funciona perfectamente para la navegación fragmento basada barra inferior cuando se quiere cerrar la aplicación cuando se presiona la parte posterior en fragmento primario.

Por otro lado, cuando abra el fragmento secundario (fragmento en fragmento) que se define como "DetailedPizza" en mi código, devolverá el estado anterior del fragmento primario. ¡Salud!

actividades dentro de la parte posterior presionada poner esto:

Fragment home = getSupportFragmentManager().findFragmentByTag("DetailedPizza"); 

    if (home instanceof FragmentDetailedPizza && home.isVisible()) { 
     if (getFragmentManager().getBackStackEntryCount() != 0) { 
      getFragmentManager().popBackStack(); 
     } else { 
      super.onBackPressed(); 
     } 

    } else { 
     //Primary fragment 
     moveTaskToBack(true); 
    } 

y poner en marcha el otro fragmento de esta manera:

Fragment someFragment = new FragmentDetailedPizza(); 
    FragmentTransaction transaction = getFragmentManager().beginTransaction(); 
    transaction.replace(R.id.container_body, someFragment, "DetailedPizza"); 
    transaction.addToBackStack("DetailedPizza"); 
    transaction.commit(); 
1

Para que ese fragmento llegado de nuevo, sólo añadir que el fragmento de backstack que desea venir en la parte posterior prensado, Ej:

button.setOnClickListener(new View.OnClickListener() { 
    @Override 
    public void onClick(View v) { 
     Fragment fragment = new LoginFragment(); 
     //replacing the fragment 
     if (fragment != null) { 
      FragmentTransaction ft = ((FragmentActivity)getContext()).getSupportFragmentManager().beginTransaction(); 
      ft.replace(R.id.content_frame, fragment); 
      ft.addToBackStack("SignupFragment"); 
      ft.commit(); 
     } 
    } 
}); 

en el caso anterior, estoy abriendo LoginFragment cuando se presiona Button button, ahora el usuario está en SignupFragment. Entonces, si se llama a addToBackStack(TAG), donde TAG = "SignupFragment", cuando se presiona el botón Atrás en LoginFragment, volvemos al SignUpFragment.

Happy Coding!

Cuestiones relacionadas