Es bien sabido que Flutter ofrece una forma muy sencilla de crear hermosas aplicaciones multiplataforma (Android e iOS, y Escritorio y Web en el canal beta actualmente).
Desde la perspectiva de un desarrollador de Android e IOS (como yo), esto puede ser cierto en muchos niveles, ya que puede crear su interfaz de usuario con código declarativo y funcional.
Utilizando conceptos sencillos como Columna o Fila, en lugar de sumergirse en archivos XML (que no son código como tal), o incluso el famoso storyboards que es a nivel de Interfaz Gráfica; que en conjunto todo esto es un pequeño infierno, aumenta la complejidad de desarrollar aplicaciones para ambas plataformas que sigan una misma línea (por ejemplo, una aplicación de una tienda en línea para un cliente que quiere su app para Android, iOS y por supuesto una web).
Si has trabajado con la API de animación de Android, sabrá que son un dolor de cabeza en muchos niveles: una interfaz compleja, muchas API (algunas de ellas en desuso) y, al final, terminarás sin saber cómo implementar tus animaciones aparte de las librerías de soporte... y sin contar con el proceso de animación en iOS que es un mundo a parte de su competidor más cercano de Android con iOS.
Este no es el caso de las animaciones de Flutter, ¡ya que solo hay una manera de implementarlas! y es común para Android e IOS, ya que recuerda que Flutter no emplea primitivas de iOS por ejemplo, si quieres implementar un botón, no emplea las primitivas de Button en Android y UIButton en iOS, si no lo dibuja TODO desde cero para cada plataforma; lo cual es excelente ya que Flutter tiene control total y gana velocidad.
Por qué Flutter facilita tanto las animaciones
En Android las animaciones implican navegar entre APIs, clases extrañas y comportamientos inconsistentes. En iOS el paradigma es completamente diferente. Recuerdo que mantener ambas versiones sincronizadas en un proyecto multicliente era una locura.
Con Flutter eso desaparece. Las animaciones son idénticas para Android, iOS, Web y escritorio. Todo se dibuja desde cero con el motor de Flutter, por lo que no depende de primitivas nativas (UIButton, View, etc.). Control total, cero sorpresas.
Ventajas reales al animar widgets en Flutter
- Mismo comportamiento en todas las plataformas
- Animaciones fluidas porque el framework controla el render
- APIs limpias y coherentes
- Gran variedad de widgets ya preparados
- Control total cuando quieres ir más allá
Tipos de animaciones en Flutter
- Animaciones implícitas
- Son las más simples. Tú cambias un valor y Flutter hace la transición. Perfectas para empezar.
- Animaciones explícitas
- Aquí controlas la animación en detalle con AnimationController, Tween, Curves y más.
- Interpoladas vs. basadas en física
- Interpoladas: definen inicio y final, y Flutter calcula la transición.
- Basadas en física: usan simulaciones como resortes y gravedad.
- Cuándo elegir cada tipo según tu caso de uso
- Implícitas: microinteracciones, simplicidad, cambios suaves.
- Explícitas: secuencias complejas, animaciones encadenadas, 3D, coordinaciones.
- Físicas: efectos realistas, rebotitos y comportamientos naturales.
Animaciones implícitas mediante Widgets
Las animaciones implícitas no son más que widgets que gestionan toda la parte difícil de la animación por ti. En realidad, estos widgets son muy similares a los que quizás ya haya implementado en su código. Estoy hablando de, por ejemplo:
- AnimatedPadding, la contraparte animada del widget Padding.
- AnimatedOpacity, contraparte animada del widget Opacity.
- Entre otras.
Estos dos ejemplos son muy puntuales, y su comportamiento se corresponde mucho con su nombre (¡ESO ES un buen nombre de clase!).
AnimatedOpacity(
opacity: show ? 1 : 0,
duration: Duration(milliseconds: 500),
child: Image.asset('assets/logo.png'),
)Cambias show y tienes una transición suave sin hacer nada más.
Estos widgets solo necesitan algunas cosas para funcionar:
- Un child como casi todo en Flutter, puede ser cualquier cosa (que puede ser cualquier widget),
- Una duración (expresada en horas, minutos, segundos, milisegundos, etc.) y un valor que debe ser administrado por un StatefulWidget. Este último punto es muy importante, ya que cada vez que se cambia el valor dentro de la función setState (por lo tanto, se reconstruye el widget), la animación se lanzará automáticamente mediante una interpolación del valor antiguo y el nuevo que en pocas palabras significa, tener una suave transición de un estado a otro.
import 'package:flutter/material.dart';
class Animation1 extends StatefulWidget {
@override
_Animation1State createState() => _Animation1State();
}
class _Animation1State extends State<Animation1> {
double opacity = 0.0;
@override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
AnimatedOpacity(
child: Image.asset(
'assets/img.png',
fit: BoxFit.fill,
),
duration: Duration(seconds: 3),
opacity: opacity,
),
FlatButton(
onPressed: _changeOpacity,
child: Text('Animate'),
)
],
);
}
void _changeOpacity() {
setState(() {
opacity = 1.0;
});
}
} 
El fragmento de código anterior cambió el valor de la variable opacidad dentro de una función setState, que se tradujo en un desvanecimiento fácil y asombroso en la transición para nuestra imagen.
Y, al final, este widget manejó todas las cosas de la animación por sí mismo. Lo único que teníamos que hacer era cambiar el estado de nuestro widget.
El poder de AnimatedContainer para animar múltiples propiedades
AnimatedContainer permite animar los elementos más comunes como lo es el ancho, alto, color, bordes, padding, radios… todo con solo actualizar el estado.
AnimatedContainer(
height: size,
width: size,
duration: Duration(seconds: 1),
decoration: BoxDecoration(
color: color,
borderRadius: BorderRadius.circular(radius),
),
);Límites de las animaciones implícitas
Cuando empiezas a encadenar widgets o necesitas secuencias, reversas, pausas o controlar intervalos, se vuelve complicado. Lo viví: un infierno de sangrías y widgets anidados. Allí entran las explícitas.
Widget AnimatedContainer
¡Esto es genial, solo puedes usar estos widgets para comenzar a usar animaciones en tu aplicación! Pero hay un problema: las animaciones vistas hasta ahora solo animan una propiedad de nuestro hijo. Eso no es muy flexible y puede causar muchos problemas de escalabilidad si simplemente ajustamos los widgets sin control, lo que obviamente conduce a un código pobre y críptico (sabes que Dart puede ser un infierno de sangría si no se escribe correctamente).
En pocas palabras, estas animaciones las podemos emplear para cosas realmente simples, sin implementar una lógica perse en el momento que queramos arrancar la animación, variar comportamientos, duraciones, revertir o detener la animación, nada de esto y mucho mas NO lo podemos hacer con estos contenedores.
La panacea: AnimatedContainer.
Su comportamiento es exactamente el mismo que el de un contenedor común, pero la mejor parte es que cualquiera de sus propiedades se puede animar. Lo único que tenemos que hacer es decidir qué cambios se le harán a nuestro hijo.
Digamos que queremos cambiar tanto la altura como el ancho de nuestro contenedor, y también su color (sí, los colores se pueden interpolar). Lo primero que debemos hacer es definir los campos de nuestro StatefulWidget:
var imgHeight = 100.0;
var imgWidth = 100.0;
var backgroundColor = Colors.white;Y ahora, nuestro contenedor:
AnimatedContainer(
height: imgHeight,
width: imgWidth,
color: backgroundColor,
child: Image.asset('assets/img.png', fit: BoxFit.fill),
duration: Duration(seconds: 3),
)Y decida cuáles serán los nuevos valores que se asignan en nuestra función setState:
void _changeValues() {
setState(() {
// new values to interpolate
imgWidth = 300;
imgHeight = 300;
backgroundColor = Colors.deepPurpleAccent;
});
} 
Como puede ver, se anima más de una propiedad al mismo tiempo utilizando AnimatedContainer.
Este es el código fuente:
Dije que cualquier propiedad se puede animar en este widget. Probemos y animemos su parámetro de decoración siguiendo los pasos anteriores:
import 'package:flutter/material.dart';
class Animation3 extends StatefulWidget {
@override
_Animation3State createState() => _Animation3State();
}
class _Animation3State extends State<Animation3> {
var imgHeight = 100.0;
var imgWidth = 100.0;
var backgroundColor = Colors.white;
var borderRadius = 0.0;
@override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
AnimatedContainer(
height: imgHeight,
width: imgWidth,
decoration: BoxDecoration(
color: backgroundColor,
borderRadius: BorderRadius.circular(borderRadius),
),
child: Image.asset('assets/img.png', fit: BoxFit.fill),
duration: Duration(seconds: 3),
),
FlatButton(
onPressed: _changeValues,
child: Text('Animate'),
)
],
);
}
void _changeValues() {
setState(() {
// new values to interpolate
imgWidth = 300;
imgHeight = 300;
borderRadius = 150.0;
backgroundColor = Colors.deepPurple;
});
}
} 
Como dije, CUALQUIER propiedad del widget Container se puede animar. :) Finalmente, incluso podemos crear una pequeña coreografía secuencial para nuestro pequeño amigo Ditto. Pero esto implicaría rastrear el estado de los campos de la clase, agregando muchas variables nuevas, muchos condicionales para establecer los nuevos valores, y hacerlo nos llevaría a una gran cantidad de repetición.
Otros ejemplos:
Opacidad animada:
AnimatedOpacity(
opacity: visible ? 1 : 0,
duration: Duration(milliseconds: 500),
)Contenedor con varias propiedades animadas:
AnimatedContainer(
duration: Duration(seconds: 1),
width: w,
height: h,
color: color,
)Ejemplo básico con AnimationController
_controller.forward();Flip 3D simple con Transform:
Transform(
transform: Matrix4.identity()..rotateY(pi * value),
alignment: Alignment.center,
child: child,
)Animaciones explícitas: control total paso a paso
A diferencia de las anteriores que solamente definimos un widget algunas propiedades y más, con las explicitas, tenemos el control TOTAL de cuando iniciamos, detenemos, revertimos… (ya entiendes no) las animaciones… PEROOO son más complejas de implementar y requieren un controlador para hacer todo esto.
El papel del AnimationController
Es el “cerebro” de la animación. Define duración, estado, repetición, dirección, pausas y más.
late final AnimationController _controller;
_controller = AnimationController(
vsync: this,
duration: Duration(seconds: 2),
)..forward();Tween, CurvedAnimation y aceleraciones
final curve = CurvedAnimation(
parent: _controller,
curve: Curves.easeOut,
);
final animation = Tween<double>(
begin: 0,
end: 300,
).animate(curve);Permiten personalizar cómo avanza la animación.
AnimatedBuilder y AnimatedWidget
Sirven para reconstruir solo la parte afectada en cada frame.
AnimatedBuilder(
animation: animation,
builder: (_, child) {
return Transform.scale(
scale: animation.value,
child: child,
);
},
child: Icon(Icons.star),
)Casos donde realmente necesitas animaciones explícitas
- Secuencias complejas
- Animaciones sincronizadas
- Animaciones 3D (como flip card)
- Juegos y elementos altamente dinámicos
- Control preciso sobre cada frame
Patrones de animación comunes en Flutter
- Hero animations (transiciones entre pantallas)
- El widget Hero permite mover un elemento entre pantallas con continuidad visual.
- Listas y grids animados (AnimatedList)
- Perfectas para añadir y eliminar ítems con suavidad.
- Animaciones escalonadas (Staggered animations)
- Útiles para animar elementos en cascada.
- Transiciones avanzadas con el paquete animations
Preguntas frecuentes
- ¿Qué widget usar para empezar a animar?
- AnimatedContainer o AnimatedOpacity.
- ¿Cómo hacer una animación 3D?
- Con Transform y un AnimationController.
- ¿Son mejores las implícitas o las explícitas?
- Depende: implícitas son rápidas; explícitas te dan control total.
- ¿Cómo evitar que una animación se sienta lenta?
- Ajusta curvas, reduce duración o suaviza cálculos en el build.
Conclusión
Esto es solo para comenzar con las animaciones. Solo quieres que tu aplicación se vea genial sin hacer un gran esfuerzo. La interfaz es simple y fácil de usar.
Después de probar animaciones implícitas, explícitas, contenedores animados y patrones como Hero, verás que Flutter te deja escalar desde lo más simple hasta lo más avanzado sin cambiar de mentalidad. Esa coherencia fue lo que más disfruté cuando pasé de Android/iOS nativos a Flutter.
Si ya dominas esto, te recomiendo explorar:
- Animaciones físicas avanzadas (SpringSimulation)
- TweenSequence para animaciones complejas
- Shared Axis Transitions (paquete animations)
- Flutter Impeller para mejoras de rendimiento