¿Cómo mantener sólo el primer fragmento añadido en la pila trasera (fragmento de superposición)?

Escenario lo que estoy tratando de lograr:

  1. Actividad de carga con dos contenedores de marco (para lista de elementos y detalles).
  2. En la hora de lanzamiento de la aplicación, agregue el listFragment en listFrame y algún infoFragment inicial en los contenedores de detailsFrame.
  3. Navegación a través de elementos de lista sin agregar cada transacción de detalle a la pila trasera (desea mantener sólo infoFragment en la pila).
  4. Tan pronto como el usuario pulsa el botón de retroceso (navegar hacia atrás) se cae de nuevo a infoFragment intial lo que se añadió en el tiempo de lanzamiento.
  5. Si la navegación posterior secuencial fallows, las aplicaciones saldrán.

Mi código:

protected override void OnCreate(Bundle savedInstanceState) { ... var listFrag = new ListFragment(); var infoFrag = new InfoFragment(); var trans = FragmentManager.BeginTransaction(); trans.Add(Resource.Id.listFrame, listFrag); trans.Add(Resource.Id.detailsFrame, infoFrag); trans.Commit(); ... } public void OnItemSelected(int id) { var detailsFrag = DetailFragment.NewInstance(id); var trans = FragmentManager.BeginTransaction(); trans.Replace(Resource.Id.detailsFrame, detailsFrag); if (FragmentManager.BackStackEntryCount == 0) { trans.AddToBackStack(null); } trans.Commit(); } 

Mi problema:

Después de que el botón de la parte posterior haya sido golpeado, infoFrag se solapa con detailFrag anterior! ¿Por qué?

El problema es que la transacción de la que está backing tiene dos pasos:

  • Eliminar infoFrag
  • Add detailsFrag (que es el primer contenedor de detalle que se agregó)

(Sabemos que debido a que la documentación This is essentially the same as calling remove(Fragment) for all currently added fragments that were added with the same containerViewId and then add(int, Fragment, String) with the same arguments given here.

Así que cada vez que el sistema está revertiendo que una transacción está revertiendo exactamente esos 2 pasos, y no dice nada sobre el último detailFrag que se agregó a él, por lo que no hace nada con él.

Puedo pensar en su caso en dos casos posibles:

  1. Mantenga una referencia en su actividad a los últimos detallesFrag utilizado y utilice el oyente BackStackChange siempre que el valor cambie de 1 a 0 (tendrá que realizar un seguimiento de los valores anteriores) también se elimina ese fragmento restante

  2. En cada oyente de clics tendrás que popBackStackImmediatly () (para eliminar la transacción anterior) y addToBackStack() en todas las transacciones. En esta solución, también puede utilizar algunos setCustomAnimation magia para asegurarse de que todo se ve bien en la pantalla (por ejemplo, utilizar una animación alfa de 0 a 0 duración 1 para evitar fragmento anterior que aparece y desaparecer de nuevo.

PD. Estoy de acuerdo en que el gestor de fragmentos / transacción debe ser un poco más inteligente a la forma en que maneja la pila de espalda en las acciones .replace (), pero esa es la forma en que lo hace.

editar:

Lo que está sucediendo es como esto (estoy añadiendo números a los detalles para hacerlo más claro). Recuerde que .replace() = .remove().add()

 Transaction.remove(info).add(detail1).addToBackStack(null) // 1st time Transaction.remove(detail1).add(detail2) // 2nd time Transaction.remove(detail2).add(detail3) // 3rd time Transaction.remove(detail3).add(detail4) // 4th time 

Así que ahora tenemos detail4 en el diseño:

 < Press back button > System pops the back stack and find the following back entry to be reversed remove(info).add(detail1); so the system makes that transaction backward. tries to remove detail1 (is not there, so it ignores) re-add(info) // OVERLAP !!! 

Por lo que el problema es que el sistema no se da cuenta de que hay un detalle4 y que la transacción fue .replace () que se suponía que debía reemplazar lo que está allí.

Puedes hacerlo:

 if (getSupportFragmentManager().getBackStackEntryCount() > 0) { getSupportFragmentManager().popBackStack(getSupportFragmentManager().getBackStackEntryAt(0).getId(), getSupportFragmentManager().POP_BACK_STACK_INCLUSIVE); } else { super.onBackPressed();} 

En tu actividad, para que tengas el primer fragmento.

No deberías tener, en tu primer fragmento, el addToBackStack. Pero, en el resto, sí.

Muy buena explicación de Budius. He leído su consejo e implementado la navegación similar, que me gustaría compartir con otros.

En lugar de reemplazar fragmentos como este:

 Transaction.remove(detail1).add(detail2) Transaction.remove(detail2).add(detail3) Transaction.remove(detail3).add(detail4) 

He añadido un fragmento de diseño de contenedor en el archivo de diseño de la actividad. Puede ser LinearLayout , RelativeLayot o FrameLayout etc .. Así que en la actividad de crear tuve esto:

 transaction.replace(R.id.HomeInputFragment, mainHomeFragment).commit(); 

mainHomeFragment es el fragmento al que quiero volver cuando presionas el botón de regreso, como infoFrag . Luego, antes de CADA NEXT transacción puse:

 fragmentManager.popBackStackImmediate(); transaction.replace(R.id.HomeInputFragment, frag2).addToBackStack(null).commit(); 

o

 fragmentManager.popBackStackImmediate(); transaction.replace(R.id.HomeInputFragment, frag3).addToBackStack(null).commit(); 

De esa manera usted no tiene que hacer un seguimiento de qué fragmento es currenty mostrando.

Usted podría simplemente anular onBackPressed y confirmar una transacción al fragmento inicial.

Estoy adivinando pero:

Has agregado la transacción para reemplazar infoFrag con 1st detailsFrag en la backstack.

Pero entonces usted substituye 1st detailsFrag con 2nd detailsFrag.

En este punto cuando haces clic de nuevo, el administrador de fragmentos no puede reemplazar limpiamente 1st detailsFrag con infoFrag como 1st detailsFrag ya se ha eliminado y reemplazado.

No sé si el comportamiento de superposición se espera o no.

Yo sugeriría la depuración del código de núcleo de Android para ver lo que está haciendo.

No estoy seguro de si se puede lograr sin decir Activity::onBackPressed() y hacer los pops a sí mismo haber añadido todas las transacciones a la backstack.

FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.