Con Android 4.2, la biblioteca de soporte obtuvo soporte para fragmentos anidados, consulte aquí . He jugado con él y encontré un comportamiento / error interesante con respecto a la pila de actividades y getChildFragmentManager () . Cuando se usa getChildFragmentManager () y addToBackStack (nombre de cadena), al presionar el botón Atrás, el sistema no corre hacia abajo en la pila de actividades al fragmento anterior. Por otro lado, cuando se usa getFragmentManager () y addToBackStack (nombre de cadena), al presionar el botón Atrás, el sistema regresa al fragmento anterior.
Para mí, este comportamiento es inesperado. Al presionar el botón de retroceso en mi dispositivo, espero que aparezca el último fragmento agregado a la pila de actividades, incluso si el fragmento se agregó a la pila de actividades en el administrador de fragmentos de los niños.
¿Es este comportamiento correcto? ¿Es este comportamiento un error? ¿Hay alguna solución para este problema?
código de muestra con getChildFragmentManager ():
public class FragmentceptionActivity extends FragmentActivity {
@Override
protected void onCreate(Bundle arg0) {
super.onCreate(arg0);
final FrameLayout wrapper1 = new FrameLayout(this);
wrapper1.setLayoutParams(new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT));
wrapper1.setId(1);
final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.WRAP_CONTENT);
params.topMargin = 0;
final TextView text = new TextView(this);
text.setLayoutParams(params);
text.setText("fragment 1");
wrapper1.addView(text);
setContentView(wrapper1);
getSupportFragmentManager().beginTransaction().addToBackStack(null)
.add(1, new Fragment1()).commit();
}
public class Fragment1 extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final FrameLayout wrapper2 = new FrameLayout(getActivity());
wrapper2.setLayoutParams(new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT));
wrapper2.setId(2);
final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.WRAP_CONTENT);
params.topMargin = 100;
final TextView text = new TextView(getActivity());
text.setLayoutParams(params);
text.setText("fragment 2");
wrapper2.addView(text);
return wrapper2;
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
getFragmentManager().beginTransaction().addToBackStack(null)
.add(2, new Fragment2()).commit();
}
}
public class Fragment2 extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final FrameLayout wrapper3 = new FrameLayout(getActivity());
wrapper3.setLayoutParams(new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT));
wrapper3.setId(3);
final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.WRAP_CONTENT);
params.topMargin = 200;
final TextView text = new TextView(getActivity());
text.setLayoutParams(params);
text.setText("fragment 3");
wrapper3.addView(text);
return wrapper3;
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
getChildFragmentManager().beginTransaction().addToBackStack(null)
.add(3, new Fragment3()).commit();
}
}
public class Fragment3 extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final FrameLayout wrapper4 = new FrameLayout(getActivity());
wrapper4.setLayoutParams(new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT));
wrapper4.setId(4);
final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.WRAP_CONTENT);
params.topMargin = 300;
final TextView text = new TextView(getActivity());
text.setLayoutParams(params);
text.setText("fragment 4");
wrapper4.addView(text);
return wrapper4;
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
getChildFragmentManager().beginTransaction().addToBackStack(null)
.add(4, new Fragment4()).commit();
}
}
public class Fragment4 extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final FrameLayout wrapper5 = new FrameLayout(getActivity());
wrapper5.setLayoutParams(new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT));
wrapper5.setId(5);
final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.WRAP_CONTENT);
params.topMargin = 400;
final TextView text = new TextView(getActivity());
text.setLayoutParams(params);
text.setText("fragment 5");
wrapper5.addView(text);
return wrapper5;
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
}
}
}
código de muestra con getFragmentManager ():
public class FragmentceptionActivity extends FragmentActivity {
@Override
protected void onCreate(Bundle arg0) {
super.onCreate(arg0);
final FrameLayout wrapper1 = new FrameLayout(this);
wrapper1.setLayoutParams(new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT));
wrapper1.setId(1);
final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.WRAP_CONTENT);
params.topMargin = 0;
final TextView text = new TextView(this);
text.setLayoutParams(params);
text.setText("fragment 1");
wrapper1.addView(text);
setContentView(wrapper1);
getSupportFragmentManager().beginTransaction().addToBackStack(null)
.add(1, new Fragment1()).commit();
}
public class Fragment1 extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final FrameLayout wrapper2 = new FrameLayout(getActivity());
wrapper2.setLayoutParams(new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT));
wrapper2.setId(2);
final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.WRAP_CONTENT);
params.topMargin = 100;
final TextView text = new TextView(getActivity());
text.setLayoutParams(params);
text.setText("fragment 2");
wrapper2.addView(text);
return wrapper2;
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
getFragmentManager().beginTransaction().addToBackStack(null)
.add(2, new Fragment2()).commit();
}
}
public class Fragment2 extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final FrameLayout wrapper3 = new FrameLayout(getActivity());
wrapper3.setLayoutParams(new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT));
wrapper3.setId(3);
final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.WRAP_CONTENT);
params.topMargin = 200;
final TextView text = new TextView(getActivity());
text.setLayoutParams(params);
text.setText("fragment 3");
wrapper3.addView(text);
return wrapper3;
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
getFragmentManager().beginTransaction().addToBackStack(null)
.add(3, new Fragment3()).commit();
}
}
public class Fragment3 extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final FrameLayout wrapper4 = new FrameLayout(getActivity());
wrapper4.setLayoutParams(new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT));
wrapper4.setId(4);
final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.WRAP_CONTENT);
params.topMargin = 300;
final TextView text = new TextView(getActivity());
text.setLayoutParams(params);
text.setText("fragment 4");
wrapper4.addView(text);
return wrapper4;
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
getFragmentManager().beginTransaction().addToBackStack(null)
.add(4, new Fragment4()).commit();
}
}
public class Fragment4 extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final FrameLayout wrapper5 = new FrameLayout(getActivity());
wrapper5.setLayoutParams(new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT));
wrapper5.setId(5);
final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.WRAP_CONTENT);
params.topMargin = 400;
final TextView text = new TextView(getActivity());
text.setLayoutParams(params);
text.setText("fragment 5");
wrapper5.addView(text);
return wrapper5;
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
}
}
}
Respuestas:
Esta solución puede ser una mejor versión de la respuesta de @Sean:
Nuevamente, preparé esta solución basada en la respuesta de @Sean anterior.
Como dijo @ AZ13, esta solución solo es factible en situaciones de fragmentos de niños de un nivel. En el caso de fragmentos de múltiples niveles, las obras se vuelven un poco complejas, por lo que recomiendo probar esta solución solo en el caso factible que he dicho. =)
Nota: Desde
getFragments
método ahora es un método privado, esta solución no funcionará. Puede consultar los comentarios para ver un enlace que sugiera una solución sobre esta situación.fuente
getFragments
ahora es público.Parece un error. Eche un vistazo a: http://code.google.com/p/android/issues/detail?id=40323
Para una solución alternativa que he usado con éxito (como se sugiere en los comentarios):
fuente
La verdadera respuesta a esta pregunta está en la función de Fragment Transaction llamada setPrimaryNavigationFragment.
Debe configurar esta función en el fragmento principal inicial cuando la actividad lo agrega. Tengo una función replaceFragment dentro de mi actividad que se ve así:
Esto le da el mismo comportamiento que si volviera a hacer clic desde el Fragmento B normal al Fragmento A, ¡excepto que ahora también está en los fragmentos secundarios!
fuente
Esta solución puede ser una mejor versión de la respuesta de @ismailarilik:
Versión de fragmento anidado
fuente
SupportFragmentManager
y en su lugar solo el EstándarFragmentManager
?Con esta respuesta, manejará la verificación de retroceso recursiva y le dará a cada fragmento la oportunidad de anular el comportamiento predeterminado. Esto significa que puede hacer que un fragmento que aloje un ViewPager haga algo especial, como desplazarse a la página que se utiliza como back-stack, o desplazarse a la página de inicio y luego, en la siguiente, presione salir.
Agregue esto a su actividad que extiende AppCompatActivity.
Agregue esto a su BaseFragment o la clase de la que puede heredar todos sus fragmentos.
fuente
Este código navegará por el árbol de administradores de fragmentos y devolverá el último que se agregó que tiene fragmentos que pueda sacar de la pila:
Llame al método:
fuente
La razón es que su actividad se deriva de FragmentActivity, que maneja la pulsación de la tecla ATRÁS (consulte la línea 173 de FragmentActivity .
En nuestra aplicación, estoy usando un ViewPager (con fragmentos) y cada fragmento puede tener fragmentos anidados. La forma en que manejé esto es por:
void onBackKeyPressed()
También tenga en cuenta que estoy usando
getChildFragmentManager()
los fragmentos para anidar correctamente los fragmentos. Puede ver una discusión y una explicación en esta publicación de desarrolladores de Android .fuente
si está utilizando un fragmento en un fragmento, utilice
getChildFragmentManager()
Si está usando un fragmento secundario y lo reemplaza, use
getParentFragmentManager()
si ambos no funcionan para ti, prueba esto
getActivity().getSupportFragmentManager()
fuente
Pude manejar la pila de fragmentos agregando al fragmento principal este método en el método onCreate View () y pasando la vista raíz.
El método isEnableFragmentBackStack () es una bandera booleana para saber cuándo estoy en el fragmento principal o en el siguiente.
Asegúrese de que cuando confirme el fragmento que debe tener una pila, debe agregar el método addToBackstack.
fuente
Esta solución puede ser mejor, porque verifica todos los niveles de fragmentos anidados:
en su actividad
onBackPressed
, simplemente puede llamarlo de esta manera:fuente
Gracias a todos por su ayuda, esta (versión modificada) funciona para mí:
NOTA: Probablemente también desee establecer el color de fondo de estos fragmentos anidados en el color de fondo de la ventana del tema de la aplicación, ya que por defecto son transparentes. Algo fuera del alcance de esta pregunta, pero se logra resolviendo el atributo android.R.attr.windowBackground y configurando el fondo de la vista Fragmento en ese ID de recurso.
fuente
Más de 5 años y este tema sigue siendo relevante. Si no desea utilizar fragmentManager.getFragments () debido a su restricción. Amplíe y use las siguientes clases:
NestedFragmentActivity.java
NestedFragment.java
Explicación:
Cada actividad y fragmento extendido de las clases anteriores maneja su propia pila para cada uno de sus hijos, y los hijos de los niños, y así sucesivamente. El backstack es simplemente un registro de etiquetas / ID de "fragmentos activos". Entonces, la advertencia es proporcionar siempre una etiqueta y / o identificación para su fragmento.
Al agregar al backstack en un childFragmentManager, también necesitará llamar a "addToParentBackStack ()". Esto asegura que la etiqueta / identificación del fragmento se agregue en el fragmento / actividad principal para posteriores estallidos.
Ejemplo:
fuente
Lo he implementado correctamente si alguien no encontró ninguna respuesta hasta ahora
simplemente agregue este método en el fragmento anidado de su hijo
fuente
Resolví este problema manteniendo el fragmento abierto actualmente en propiedad de la actividad. Entonces anulo el método
Así es como agrego un fragmento secundario al fragmento abierto actualmente desde dentro de sí mismo.
Este es el diseño xml del fragmento principal y el fragmento agregado
fuente
Después de observar algunas de las soluciones presentadas aquí, descubrí que para permitir flexibilidad y control para el fragmento principal en cuanto a cuándo hacer estallar la pila o cuándo debe ignorar la acción de retroceso, prefiero usar dicha implementación:
Definición de una interfaz "ParentFragment":
}
Anulando "onBackPressed" en la actividad principal (o en BaseActivity):
Y luego permita que el fragmento principal se maneje como desee, por ejemplo:
Esto permite evitar pensar que hay algún fragmento secundario legítimo para eliminar cuando se usa un paginador de vista, por ejemplo (y el recuento de entradas de la pila de retroceso> 0).
fuente
Si tiene un
DialogFragment
que a su vez tiene fragmentos anidados, la 'solución alternativa' es un poco diferente. En lugar de establecer unonKeyListener
en elrootView
, deberá hacerlo con elDialog
. También estarás configurando unDialogInterface.OnKeyListener
y noView
uno. ¡Por supuesto, recuerdaaddToBackStack
!Esto es lo que debe hacer dentro de onCreateDialog
fuente
Dialog
(noDialogFragment
) y el oyente que usa esDialogInterface.OnKeyListener
: el código está funcionando y completo (y en uso). ¿Por qué no proporciona su situación y quizás yo pueda ayudar?para ChildFragments esto funciona ...
fuente