Sabemos que tienes muchas opciones cuando vuelas (perdón, «animas») con Flutter, así que gracias por elegir AnimatedBuilder y AnimatedWidget. Un momento… ¡no! Flutter tiene muchos widgets de animación, pero, a diferencia de las aerolíneas comerciales, cada uno sirve para un tipo de tarea diferente. No hay duda de que puedes lograr la misma animación con métodos distintos, pero usar el widget adecuado para cada tarea te facilita mucho la vida.
En este artículo, te explicamos por qué es mejor usar AnimatedBuilder o AnimatedWidget en lugar de otros widgets de animación, y te mostramos cómo hacerlo. Imagina que quieres agregar animación a tu app (este artículo forma parte de una serie en la que te explicamos por qué es recomendable usar cada tipo de widget de animación). La animación que te interesa se repite algunas veces o necesitas que se detenga y se reanude cuando el usuario realiza una acción, como tocar con el dedo. Debido a que hace falta configurar acciones (como repetir, detener o iniciar), tienes que usar una animación explícita.
Seguramente recuerdes que hay dos categorías generales de animaciones en Flutter: explícitas e implícitas. Las animaciones explícitas requieren un controlador, mientras que las implícitas no lo necesitan. En el artículo anterior sobre animaciones explícitas integradas, hablamos acerca de los controladores de animaciones. Consúltalo si quieres obtener más información al respecto.
En fin, si decidiste que necesitas una animación explícita, puedes elegir entre una gran variedad de clases de estas animaciones. Dichas clases suelen denominarse FooTransition, donde Foo hace referencia a la propiedad que intentas animar. Te recomiendo que veas si puedes usar uno de estos widgets para lograr tu objetivo, antes de explorar en más detalle el universo de AnimatedWidget y AnimatedBuilder. Hay una enorme selección de widgets que prácticamente sirve para lo que se te ocurra: rotar, posicionar, alinear, difuminar, cambiar el estilo de texto y mucho más. Además, puedes combinarlos para, por ejemplo, rotar y difuminar. Si ninguno de estos widgets integrados puede hacer lo que buscas, puedes crear uno tú mismo con AnimatedWidget o AnimatedBuilder.
Ejemplo específico
Para entender esto con más claridad, analicemos una situación particular: quiero compilar una app que tenga una nave espacial extraterrestre con una animación de un haz de luz.
Dibujé un haz de luz con degradado que va de amarillo a transparente y empieza a difuminarse exactamente al medio. Después, recorté la forma del “haz de luz” con un comando de path clipper.
https://medium.com/media/9d8ce77b4a61b1cc662bd2021cd06571/href
Quiero crear una animación descendente en el haz, que empiece en el centro del degradado y que se repita una y otra vez. Para eso, necesito crear una animación explícita. Lamentablemente, no existe una animación explícita integrada que anime degradados con forma de embudo, pero sí puedes lograrlo con AnimatedWidget y AnimatedBuilder.
AnimatedBuilder
Para animar el haz de luz, voy a incorporar el código del degradado en un widget de AnimatedBuilder. Dicho código debe ir en la función de compilación, que es la que AnimatedBuilder invoca al compilar.
Después, hace falta un controlador para activar la animación. El controlador proporciona los valores que AnimatedBuilder usa para generar versiones nuevas de la animación, marco por marco. Al igual que en el artículo anterior, realizo esta tarea en la clase SingleTickerProviderStateMixin y activo el controlador en la función initState para que se cree una sola vez. Creo el controlador en initState y no en el método de compilación para evitar crearlo muchas veces, ya que quiero que proporcione valores nuevos de animación en cada marco. Al crear un objeto nuevo en initState, agrego un método de desecho y le indico a Flutter que puede deshacerse del controlador una vez que el widget principal ya no esté en pantalla.
Luego, paso el controlador a AnimatedBuilder y la animación funciona como estaba previsto.
https://medium.com/media/85187c006d79a4d6eca10e01c79bbc2b/href
Tal vez recuerdes que en el artículo sobre TweenAnimationBuilder usamos el parámetro secundario para optimizar el rendimiento, algo que también podemos hacer con AnimatedBuilder. En resumen, si tenemos un objeto que nunca cambia durante la animación, podemos compilarlo por adelantado y pasarlo a AnimatedBuilder.
En este caso específico, existe una mejor manera de lograr lo mismo: darle a BeamClipper un constructor const y hacer que lo ejecute. Usamos menos código y el objeto se crea al momento de la compilación, lo que acelera el proceso todavía más. No obstante, hay ocasiones en que codificas algo que no tiene un constructor const y ese es un claro ejemplo de cuándo usar el parámetro secundario opcional que ya mencionamos.
AnimatedWidget
Ya tenemos nuestra animación, pero el método de compilación que contiene el código de AnimatedBuilder es un poco extenso. Si el método de compilación que usas ya es difícil de leer, llegó el momento de refactorizar el código.
Puedes extraer el código de AnimatedBuilder y llevarlo a otro widget, pero eso significaría colocar un método de compilación dentro de otro, algo que no tiene mucho sentido. En cambio, puedes lograr la misma animación si creas un widget nuevo que extienda AnimatedWidget. Para ser coherente con el uso de FooTransition para las animaciones explícitas, usaré el nombre BeamTransition. Ahora, paso el controlador de animación a BeamTransition y reutilizo el contenido de la función de compilación de AnimatedBuilder.
https://medium.com/media/2706bb6ba3d6d4837936792805c00e5d/href
Al igual que con AnimatedBuilder (si corresponde), puedo optimizar el rendimiento agregando un parámetro secundario a mi widget para que se compile por adelantando, y no cada vez que realizo la animación. A modo de recordatorio: en este ejemplo, hacer que BeamClipper use un constructor const es el método más eficiente.
Entonces, ¿qué debo usar?
Acabamos de ver cómo AnimatedBuilder y AnimatedWidget pueden usarse indistintamente para lograr el mismo tipo de animaciones explícitas cuando no consigues una animación integrada que haga lo que estás buscando. La pregunta es, ¿cuál conviene usar? La verdad, depende de ti. En términos generales, recomiendo crear widgets individuales, cada uno con una tarea separada (en este caso, una animación).
Si es así, lo óptimo es usar AnimatedWidget siempre que sea posible. Sin embargo, si el widget principal que usas para crear el controlador de la animación es simple, quizá resulte innecesario agregar tanto código para crear un widget independiente por separado. En ese caso, basta con usar AnimatedBuilder.
Este artículo es la versión escrita del video que figura a continuación. Haz clic debajo si quieres verlo:
https://medium.com/media/c67252c760e8dbd66c0f6df2aa09880b/href
Este artículo forma parte de una serie. Encuentra los demás en la siguiente lista:
- Aspectos básicos de la animación en Flutter con animaciones implícitas
- Animaciones implícitas personalizadas en Flutter con TweenAnimationBuilder
- Animaciones direccionales con las animaciones explícitas integradas
- ¿Cuándo debo usar AnimatedBuilder o AnimatedWidget? (El artículo de esta página)
- Todo lo que debes saber sobre animaciones explícitas (próximamente)
Source: Google Dev