vida studio navegar fragments example entre dinamicos desde ciclo boton activity abrir android android-fragments fragmenttransaction android-nested-fragment fragment-animation

example - navegar entre fragments android studio



Fragmentos anidados transicionando incorrectamente (2)

Creo que he encontrado una manera de resolver esto usando Fragment # onCreateAnimator. Un gif de la transición se puede ver aquí: https://imgur.com/94AvrW4 .

Hice una PR para las pruebas, hasta ahora está funcionando como esperaba y sobrevivió a los cambios de configuración y al soporte del botón Atrás. Aquí está el enlace https://github.com/zafrani/NestedFragmentTransitions/pull/1/files#diff-c120dd82b93c862b01c2548bdcafcb20R25

La BaseFragment para los fragmentos de Padres e Hijos está haciendo esto para onCreateAnimator ()

override fun onCreateAnimator(transit: Int, enter: Boolean, nextAnim: Int): Animator { if (isConfigChange) { resetStates() return nothingAnim() } if (parentFragment is ParentFragment) { if ((parentFragment as BaseFragment).isPopping) { return nothingAnim() } } if (parentFragment != null && parentFragment.isRemoving) { return nothingAnim() } if (enter) { if (isPopping) { resetStates() return pushAnim() } if (isSuppressing) { resetStates() return nothingAnim() } return enterAnim() } if (isPopping) { resetStates() return popAnim() } if (isSuppressing) { resetStates() return nothingAnim() } return exitAnim() }

Los booleanos se configuran en diferentes escenarios que son más fáciles de ver en el RP.

Las funciones de animación son:

private fun enterAnim(): Animator { return AnimatorInflater.loadAnimator(activity, R.animator.fragment_enter) } private fun exitAnim(): Animator { return AnimatorInflater.loadAnimator(activity, R.animator.fragment_exit) } private fun pushAnim(): Animator { return AnimatorInflater.loadAnimator(activity, R.animator.fragment_push) } private fun popAnim(): Animator { return AnimatorInflater.loadAnimator(activity, R.animator.fragment_pop) } private fun nothingAnim(): Animator { return AnimatorInflater.loadAnimator(activity, R.animator.fragment_nothing) }

Dejará la pregunta abierta en caso de que alguien encuentre una mejor manera.

Hola buenos programadores de desbordamiento de pila! He pasado una buena semana con este problema y ahora estoy muy desesperado por una solución.

El escenario

Estoy usando android.app.Fragment no debe confundirse con los fragmentos de soporte.

Tengo 6 fragmentos de niños llamados

  • FragmentOne
  • FragmentTwo
  • FragmentThree
  • FragmentA
  • FragmentB
  • FragmentC

Tengo 2 fragmentos de padres llamados:

  • FragmentNumeric
  • FragmentAlpha

Tengo 1 actividad llamada

  • MainActivity

Se comportan en lo siguiente:

  • Los fragmentos secundarios son fragmentos que solo muestran una vista, no muestran ni contienen fragmentos.
  • Los fragmentos primarios llenan toda su vista con un solo fragmento secundario. Son capaces de reemplazar el fragmento de niño con otros fragmentos de niño.
  • La actividad llena la mayor parte de su vista con un fragmento padre. Puede reemplazarlo con otros fragmentos parentales. Entonces, en cualquier momento, la pantalla solo muestra un fragmento secundario.

Como probablemente has adivinado,

FragmentNumeric muestra fragmentos secundarios FragmentOne , FragmentTwo y FragmentThree .

FragmentAlpha muestra fragmentos secundarios FragmentA , FragmentB y FragmentC .

El problema

Estoy tratando de hacer una transición / animar los fragmentos de padres e hijos. Los fragmentos del niño hacen la transición suavemente y como se espera. Sin embargo, cuando hago la transición a un nuevo fragmento padre, se ve terrible. El fragmento secundario parece que ejecuta una transición independiente desde su fragmento primario. Y el fragmento secundario parece que también se eliminó del fragmento principal. Un gif se puede ver aquí https://imgur.com/kOAotvk . Observe lo que sucede cuando hago clic en Mostrar alfa.

Las preguntas y respuestas más cercanas que pude encontrar están aquí: los fragmentos anidados desaparecen durante la animación de transición, sin embargo, todas las respuestas no son satisfactorias.

Animator XML Files

Tengo los siguientes efectos de animación (la duración es larga para propósitos de prueba):

fragment_enter.xml

<?xml version="1.0" encoding="utf-8"?> <set> <objectAnimator xmlns:android="http://schemas.android.com/apk/res/android" android:duration="4000" android:interpolator="@android:anim/linear_interpolator" android:propertyName="xFraction" android:valueFrom="1.0" android:valueTo="0" /> </set>

fragment_exit.xml

<?xml version="1.0" encoding="utf-8"?> <set> <objectAnimator xmlns:android="http://schemas.android.com/apk/res/android" android:duration="4000" android:interpolator="@android:anim/linear_interpolator" android:propertyName="xFraction" android:valueFrom="0" android:valueTo="-1.0" /> </set>

fragmento_pop.xml

<?xml version="1.0" encoding="utf-8"?> <set> <objectAnimator xmlns:android="http://schemas.android.com/apk/res/android" android:duration="4000" android:interpolator="@android:anim/linear_interpolator" android:propertyName="xFraction" android:valueFrom="0" android:valueTo="1.0" /> </set>

fragment_push.xml

<?xml version="1.0" encoding="utf-8"?> <set> <objectAnimator xmlns:android="http://schemas.android.com/apk/res/android" android:duration="4000" android:interpolator="@android:anim/linear_interpolator" android:propertyName="xFraction" android:valueFrom="-1.0" android:valueTo="0" /> </set>

fragment_nothing.xml

<?xml version="1.0" encoding="utf-8"?> <set> <objectAnimator xmlns:android="http://schemas.android.com/apk/res/android" android:duration="4000" /> </set>

MainActivity.kt

Cosas a considerar: el primer fragmento padre, FragmentNumeric, no tiene efectos de entrada, por lo que siempre está listo para la actividad y no tiene efectos de salida porque no hay nada que salga. También estoy usando FragmentTransaction#add with it, mientras que FragmentAlpha está usando FragmentTransaction#replace

class MainActivity : AppCompatActivity { fun showFragmentNumeric(){ this.fragmentManager.beginTransaction() .setCustomAnimations(R.animator.fragment_nothing, R.animator.fragment_nothing, R.animator.fragment_push, R.animator.fragment_pop) .add(this.contentId, FragmentNumeric(), "FragmentNumeric") .addToBackStack("FragmentNumeric") .commit() } fun showFragmentAlpha(){ this.fragmentManager.beginTransaction() .setCustomAnimations(R.animator.fragment_enter, R.animator.fragment_exit, R.animator.fragment_push, R.animator.fragment_pop) .replace(this.contentId, FragmentAlpha(), "FragmentAlpha") .addToBackStack("FragmentAlpha") .commit() } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) if (savedInstanceState == null) { showFragmentNumeric() } } }

FragmentoNumérico

Hace lo mismo que la actividad en términos de mostrar rápidamente su primer fragmento secundario.

class FragmentNumeric : Fragment { fun showFragmentOne(){ this.childFragmentManager.beginTransaction() .setCustomAnimations(R.animator.fragment_nothing, R.animator.fragment_nothing, R.animator.fragment_push, R.animator.fragment_pop) .add(this.contentId, FragmentOne(), "FragmentOne") .addToBackStack("FragmentOne") .commit() } fun showFragmentTwo(){ this.childFragmentManager.beginTransaction() .setCustomAnimations(R.animator.fragment_enter, R.animator.fragment_exit, R.animator.fragment_push, R.animator.fragment_pop) .replace(this.contentId, FragmentTwo(), "FragmentTwo") .addToBackStack("FragmentTwo") .commit() } fun showFragmentThree(){ this.childFragmentManager.beginTransaction() .setCustomAnimations(R.animator.fragment_enter, R.animator.fragment_exit, R.animator.fragment_push, R.animator.fragment_pop) .replace(this.contentId, FragmentThree(), "FragmentThree") .addToBackStack("FragmentThree") .commit() } override fun onViewCreated(view: View?, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) if (savedInstanceState == null) { if (this.childFragmentManager.backStackEntryCount <= 1) { showFragmentOne() } } } }

Otros fragmentos

FragmentAlpha sigue el mismo patrón que FragmentNumeric, reemplazando los Fragmentos Uno, Dos y Tres con los Fragmentos A, B y C, respectivamente.

Los fragmentos secundarios solo muestran la siguiente vista XML y configuran su escucha de texto y de clic de botón dinámicamente para llamar a una función desde el fragmento principal o la actividad.

view_child_example.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/background" android:clickable="true" android:focusable="true" android:orientation="vertical"> <TextView android:id="@+id/view_child_example_header" style="@style/Header" android:layout_width="match_parent" android:layout_height="wrap_content" /> <Button android:id="@+id/view_child_example_button" android:layout_width="match_parent" android:layout_height="wrap_content" /> </LinearLayout>

Usando dagger y algunos contratos, tengo los fragmentos secundarios que llaman a los fragmentos de sus padres y las actividades de hospedaje haciendo algo como lo siguiente:

FragmentOne establece el botón de escucha del clic para hacer:

(parentFragment as FragmentNumeric).showFragmentTwo()

FragmentTwo establece el botón de escucha del clic para hacer:

(parentFragment as FragmentNumeric).showFragmentThree()

FragmentThree es diferente, configurará el detector de clics para que haga:

(activity as MainActivity).showFragmentAlpha()

¿Alguien tiene una solución para este problema?

Actualización 1

He agregado un proyecto de ejemplo según lo solicitado: https://github.com/zafrani/NestedFragmentTransitions

Una diferencia en eso y en la de mi video original es que el fragmento primario ya no usa una vista con la propiedad xFraction. Así que parece que la animación de entrada ya no tiene ese efecto de superposición. Sin embargo, todavía elimina el fragmento secundario del padre y los anima uno al lado del otro. Una vez que se completa la animación, el Fragmento Tres se reemplaza con el Fragmento A al instante.

Actualización 2

Tanto la vista de fragmentos primaria como la secundaria están utilizando la propiedad xFraction. La clave es suprimir la animación del niño cuando el padre está animando.


Usted está obteniendo un resultado tan conectado, porque está usando animaciones de salida para su Fragmento. Básicamente, tenemos tales problemas con la animación de Fragmentos cada vez, y finalmente pasamos de la animación de Fragmentos de origen a usar la propia, cada vez que realizamos la transición.

1) Para verificar este comportamiento, puede eliminar la animación de salida para el fragmento, y todo estará bien. En la mayoría de los casos, debería ser suficiente, porque la animación de salida es muy específica y se usa solo para la gestión de fragmentos individuales (no en su caso, con niños)

getFragmentManager().beginTransaction() .setCustomAnimations(R.animator.enter_anim_frag1, 0, R.animator.enter_anim_frag2, 0) .replace(xxx, Xxx1, Xxx2) .addToBackStack(null) .commit()

2) Otra opción, que podría ser una suite, es pensar en la estructura de la aplicación y tratar de evitar reemplazar Fragmento por animación. En caso de que necesite reemplazar, no use la animación, y puede agregar cualquier animación (incluyendo tanto entrar como salir), pero solo agregando.