Aquí está el escenario: La actividad contiene un fragmento A
, que a su vez se usa getChildFragmentManager()
para agregar fragmentos A1
y A2
de onCreate
esa manera:
getChildFragmentManager()
.beginTransaction()
.replace(R.id.fragmentOneHolder, new FragmentA1())
.replace(R.id.fragmentTwoHolder, new FragmentA2())
.commit()
Hasta ahora todo va bien, todo está funcionando como se esperaba.
Luego ejecutamos la siguiente transacción en la Actividad:
getSupportFragmentManager()
.beginTransaction()
.setCustomAnimations(anim1, anim2, anim1, anim2)
.replace(R.id.fragmentHolder, new FragmentB())
.addToBackStack(null)
.commit()
Durante la transición, las enter
animaciones del fragmento se B
ejecutan correctamente, pero los fragmentos A1 y A2 desaparecen por completo . Cuando revertimos la transacción con el botón Atrás, se inicializan correctamente y se muestran normalmente durante la popEnter
animación.
En mi breve prueba, se volvió más extraño: si configuro las animaciones para los fragmentos secundarios (ver más abajo), la exit
animación se ejecuta de forma intermitente cuando agregamos un fragmentoB
getChildFragmentManager()
.beginTransaction()
.setCustomAnimations(enter, exit)
.replace(R.id.fragmentOneHolder, new FragmentA1())
.replace(R.id.fragmentTwoHolder, new FragmentA2())
.commit()
El efecto que quiero lograr es simple: quiero que se ejecute la animación exit
(¿o debería ser popExit
?) En el fragmento A
(anim2), animando todo el contenedor, incluidos sus elementos secundarios anidados.
¿Hay alguna forma de lograrlo?
Editar : encuentre un caso de prueba aquí
Edit2 : Gracias a @StevenByle por empujarme a seguir intentando con las animaciones estáticas. Aparentemente, puede configurar animaciones por operación (no globales para toda la transacción), lo que significa que los niños pueden tener un conjunto de animación estática indefinida, mientras que su padre puede tener una animación diferente y todo se puede comprometer en una transacción . Vea la discusión a continuación y el proyecto de caso de prueba actualizado .
R.id.fragmentHolder
con respecto a A, A1, A2, etc.?changeFragment
método solo una vez?Respuestas:
Para evitar que el usuario vea que los fragmentos anidados desaparecen cuando el fragmento principal se elimina / reemplaza en una transacción, puede "simular" esos fragmentos que aún están presentes proporcionando una imagen de ellos, tal como aparecieron en la pantalla. Esta imagen se utilizará como fondo para el contenedor de fragmentos anidados, por lo que incluso si las vistas del fragmento anidado desaparecen, la imagen simulará su presencia. Además, no veo que perder la interactividad con las vistas del fragmento anidado sea un problema porque no creo que desee que el usuario actúe sobre ellos cuando están en el proceso de ser eliminado (probablemente como una acción del usuario como bien).
Hice un pequeño ejemplo con la configuración de la imagen de fondo (algo básico).
fuente
Así que parece haber muchas soluciones alternativas para esto, pero según la respuesta de @ Jayd16, creo que encontré una solución general bastante sólida que aún permite animaciones de transición personalizadas en fragmentos secundarios y no requiere hacer un caché de mapa de bits del diseño.
Tenga una
BaseFragment
clase que se extiendaFragment
y haga que todos sus fragmentos extiendan esa clase (no solo los fragmentos secundarios).En esa
BaseFragment
clase, agregue lo siguiente:Desafortunadamente, requiere reflexión; sin embargo, dado que esta solución es para la biblioteca de soporte, no corre el riesgo de que cambie la implementación subyacente a menos que actualice su biblioteca de soporte. Si está creando la biblioteca de soporte desde la fuente, puede agregar un acceso para el siguiente ID de recurso de animación
Fragment.java
y eliminar la necesidad de reflexión.Esta solución elimina la necesidad de "adivinar" la duración de la animación del padre (de modo que la animación de "no hacer nada" tenga la misma duración que la animación de salida del padre) y le permite seguir haciendo animaciones personalizadas en los fragmentos secundarios (por ejemplo, si ' intercambiando fragmentos de niños con diferentes animaciones).
fuente
mNextAnim
ahora está dentro de unmAnimationInfo
objeto. Puede acceder a él así:Field animInfoField = Fragment.class.getDeclaredField("mAnimationInfo");
animInfoField.setAccessible(true);
Object animationInfo = animInfoField.get(fragment);
Field nextAnimField = animationInfo.getClass().getDeclaredField("mNextAnim");
val nextAnimResource = nextAnimField.getInt(animationInfo);
para reemplazar la líneaint nextAnimResource = nextAnimField.getInt(fragment);
Pude encontrar una solución bastante limpia. En mi opinión, es el menos hacky, y si bien esta es técnicamente la solución de "dibujar un mapa de bits", al menos está abstraída por el fragmento lib.
Asegúrese de que los fragmentos de su hijo anulen una clase principal con esto:
Si tenemos una animación de salida en los fragmentos secundarios, se animarán en lugar de parpadear. Podemos aprovechar esto al tener una animación que simplemente dibuja los fragmentos secundarios en alfa completo durante un tiempo. De esta manera, permanecerán visibles en el fragmento principal mientras se anima, dando el comportamiento deseado.
El único problema que se me ocurre es hacer un seguimiento de esa duración. Tal vez podría configurarlo en un número grande, pero me temo que eso podría tener problemas de rendimiento si todavía está dibujando esa animación en alguna parte.
fuente
Estoy publicando mi solución para mayor claridad. La solución es bastante simple. Si está intentando imitar la animación de la transacción del fragmento principal, simplemente agregue una animación personalizada a la transacción del fragmento secundario con la misma duración. Ah, y asegúrese de configurar la animación personalizada antes de agregar ().
El xml para R.anim.none (el tiempo de animación de entrada / salida de mis padres es de 250 ms)
fuente
fragmentTransaction.setCustomAnimations(R.anim.none, 0, R.anim.none, R.anim.none)
Entiendo que es posible que esto no pueda resolver completamente su problema, pero tal vez se adapte a las necesidades de otra persona, puede agregar
enter
/exit
ypopEnter
/popExit
animaciones a los de sus hijosFragment
que en realidad no mueven / animan losFragment
s. Siempre que las animaciones tengan la misma duración / desplazamiento que susFragment
animaciones principales , parecerán que se mueven / animan con la animación principal.fuente
puedes hacer esto en el fragmento secundario.
fuente
@@@@@@@@@@@@@@@@@@@@@@@@@@
EDITAR: Terminé sin implementar esta solución ya que hubo otros problemas que esto tiene. Square lanzó recientemente 2 bibliotecas que reemplazan los fragmentos. Yo diría que esta podría ser una alternativa mejor que intentar piratear fragmentos para que hagan algo que Google no quiere que hagan.
http://corner.squareup.com/2014/01/mortar-and-flow.html
@@@@@@@@@@@@@@@@@@@@@@@@@@
Pensé que pondría esta solución para ayudar a las personas que tengan este problema en el futuro. Si sigue la conversación de los carteles originales con otras personas y observa el código que publicó, verá que el cartel original finalmente llega a la conclusión de usar una animación no operativa en los fragmentos secundarios mientras anima el fragmento principal. Esta solución no es ideal, ya que le obliga a realizar un seguimiento de todos los fragmentos secundarios, lo que puede resultar engorroso cuando se utiliza un ViewPager con FragmentPagerAdapter.
Como utilizo Child Fragments en todas partes, se me ocurrió esta solución que es eficiente y modular (por lo que se puede quitar fácilmente) en caso de que alguna vez lo solucionen y esta animación no operativa ya no sea necesaria.
Hay muchas formas de implementar esto. Elegí usar un singleton, y lo llamo ChildFragmentAnimationManager. Básicamente, realizará un seguimiento de un fragmento secundario para mí en función de su padre y aplicará una animación no operativa a los niños cuando se le solicite.
A continuación, debe tener una clase que extienda Fragmento que se extiendan todos sus Fragmentos (al menos sus Fragmentos secundarios). Ya tenía esta clase y la llamo BaseFragment. Cuando se crea una vista de fragmentos, la agregamos al ChildFragmentAnimationManager y la eliminamos cuando se destruye. Puede hacer esto en Adjuntar / Separar u otros métodos de coincidencia en la secuencia. Mi lógica para elegir Crear / Destruir Vista fue porque si un Fragmento no tiene una Vista, no me importa animarlo para que se siga viendo. Este enfoque también debería funcionar mejor con ViewPagers que usan Fragments, ya que no hará un seguimiento de cada FragmentPagerAdapter que contiene un FragmentPagerAdapter, sino solo 3.
Ahora que todos sus Fragmentos están almacenados en la memoria por el fragmento principal, puede llamar a animarlos de esta manera, y sus fragmentos secundarios no desaparecerán.
Además, para que lo tenga, aquí está el archivo no_anim.xml que va en su carpeta res / anim:
Nuevamente, no creo que esta solución sea perfecta, pero es mucho mejor que para cada instancia que tenga un fragmento secundario, implementando código personalizado en el fragmento principal para realizar un seguimiento de cada niño. He estado allí y no es divertido.
fuente
Creo que encontré una mejor solución a este problema que hacer una instantánea del fragmento actual en un mapa de bits como sugirió Luksprog.
El truco consiste en ocultar el fragmento que se está eliminando o separando y solo después de que se hayan completado las animaciones, el fragmento se elimina o se separa en su propia transacción de fragmentos.
Imagina que tenemos
FragmentA
yFragmentB
, ambos con subfragmentos. Ahora, cuando lo haría normalmente:En cambio lo haces
Ahora para la implementación del Fragmento:
fuente
Estaba teniendo el mismo problema con el fragmento de mapa. Siguió desapareciendo durante la animación de salida de su fragmento contenedor. La solución es agregar animación para el fragmento de mapa secundario que lo mantendrá visible durante la animación de salida del fragmento principal. La animación del fragmento secundario mantiene su alfa al 100% durante su período de duración.
Animación: res / animator / keep_child_fragment.xml
Luego, la animación se aplica cuando el fragmento de mapa se agrega al fragmento principal.
Fragmento principal
Finalmente, la duración de la animación del fragmento secundario se establece en un archivo de recursos.
valores / integers.xml
fuente
Para animar la desaparición de fragmentos neasted, podemos forzar la pila de retroceso en ChildFragmentManager. Esto disparará la animación de transición. Para hacer esto, necesitamos ponernos al día con el evento OnBackButtonPressed o escuchar los cambios de backstack.
Aquí hay un ejemplo con código.
fuente
Recientemente me encontré con este problema en mi pregunta: fragmentos anidados que hacen una transición incorrecta
Tengo una solución que resuelve esto sin guardar un mapa de bits, ni usar la reflexión ni ningún otro método insatisfactorio.
Se puede ver un proyecto de ejemplo aquí: https://github.com/zafrani/NestedFragmentTransitions
Un GIF del efecto se puede ver aquí: https://imgur.com/94AvrW4
En mi ejemplo, hay 6 fragmentos secundarios, divididos entre dos fragmentos principales. Puedo lograr las transiciones para entrar, salir, hacer estallar y empujar sin ningún problema. Los cambios de configuración y las prensas posteriores también se gestionan con éxito.
La mayor parte de la solución está en la función onCreateAnimator de mi BaseFragment (el fragmento extendido por mis hijos y los fragmentos principales) que se ve así:
La actividad y el fragmento padre son responsables de establecer los estados de estos valores booleanos. Es más fácil ver cómo y dónde desde mi proyecto de ejemplo.
No estoy usando fragmentos de soporte en mi ejemplo, pero se puede usar la misma lógica con ellos y su función onCreateAnimation
fuente
Una forma sencilla de solucionar este problema es utilizar la
Fragment
clase de esta biblioteca en lugar de la clase de fragmento de biblioteca estándar:https://github.com/marksalpeter/contract-fragment
Como nota al margen, el paquete también contiene un patrón de delegado útil llamado
ContractFragment
que puede resultarle útil para crear sus aplicaciones aprovechando la relación de fragmento padre-hijo.fuente
De la respuesta anterior de @kcoppock,
si tiene Actividad-> Fragmento-> Fragmentos (apilamiento múltiple, lo siguiente ayuda), una edición menor a la mejor respuesta en mi humilde opinión.
fuente
Mi problema estaba en la eliminación del fragmento principal (ft.remove (fragment)), las animaciones secundarias no estaban sucediendo.
El problema básico es que los fragmentos secundarios se DESTRUYEN inmediatamente ANTES de que el fragmento principal salga de la animación.
Las animaciones personalizadas de los fragmentos secundarios no se ejecutan al eliminar el fragmento principal
Como otros han eludido, esconder al PADRE (y no al niño) antes de la remoción del PADRE es el camino a seguir.
Si realmente desea eliminar el padre, probablemente debería configurar un oyente en su animación personalizada para saber cuándo finaliza la animación, de modo que pueda finalizar con seguridad el fragmento principal (eliminar). Si no hace esto, de manera oportuna, podría terminar matando la animación. La animación NB se realiza en una cola asincrónica propia.
Por cierto, no necesita animaciones personalizadas en el fragmento secundario, ya que heredarán las animaciones principales.
fuente
El problema está solucionado en
androidx.fragment:fragment:1.2.0-alpha02
. Consulte https://issuetracker.google.com/issues/116675313 para obtener más detalles.fuente
Hilo antiguo, pero en caso de que alguien se tropiece aquí:
Todos los enfoques anteriores me parecen muy poco atractivos, la solución de mapa de bits es muy sucia y no funciona; los otros requieren que los fragmentos secundarios conozcan la duración de la transición utilizada en la transacción utilizada para crear el fragmento secundario en cuestión. Una mejor solución en mis ojos es algo como lo siguiente:
Simplemente ocultamos el fragmento actual y agregamos el nuevo fragmento, cuando la animación ha terminado eliminamos el fragmento antiguo. De esta forma se maneja en un solo lugar y no se crea ningún mapa de bits.
fuente