Animaciones Hero
Cómo animar un widget para volar entre dos pantallas.
Probablemente has visto animaciones hero muchas veces. Por ejemplo, una pantalla muestra una lista de miniaturas que representan artículos a la venta. Al seleccionar un artículo, este vuela hacia una nueva pantalla que contiene más detalles y un botón de "Comprar". Hacer volar una imagen de una pantalla a otra se llama una animación hero en Flutter, aunque a veces se hace referencia al mismo movimiento como una transición de elemento compartido.
Es posible que desees ver este video de un minuto que presenta el widget Hero:
Esta guía demuestra cómo construir animaciones hero estándar y animaciones hero que transforman la imagen de una forma circular a una forma cuadrada durante el vuelo.
Una Route describe una página o pantalla en una app de Flutter.
Puedes crear esta animación en Flutter con widgets Hero. A medida que el hero se anima desde la ruta de origen a la de destino, la ruta de destino (menos el hero) aparece gradualmente. Típicamente, los héroes son pequeñas partes de la UI, como imágenes, que ambas rutas tienen en común. Desde la perspectiva del usuario, el hero "vuela" entre las rutas. Esta guía muestra cómo crear las siguientes animaciones hero:
Standard hero animations
Una animación hero estándar hace volar al hero desde una ruta hacia una nueva ruta, generalmente aterrizando en una ubicación diferente y con un tamaño diferente.
El siguiente video (grabado a velocidad lenta) muestra un ejemplo típico. Tocar los aletas en el centro de la ruta las hace volar hacia la esquina superior izquierda de una nueva ruta azul, a un tamaño más pequeño. Tocar las aletas en la ruta azul (o usar el gesto del dispositivo para volver a la ruta anterior) hace que las aletas vuelen de regreso a la ruta original.
Radial hero animations
En una animación hero radial, a medida que el hero vuela entre rutas, su forma parece cambiar de circular a rectangular.
El siguiente video (grabado a velocidad lenta), muestra un ejemplo de una animación hero radial. Al inicio, una fila de tres imágenes circulares aparece en la parte inferior de la ruta. Tocar cualquiera de las imágenes circulares hace volar esa imagen hacia una nueva ruta que la muestra con una forma cuadrada. Tocar la imagen cuadrada hace volar al hero de regreso a la ruta original, mostrada con una forma circular.
Antes de pasar a las secciones específicas de animaciones hero estándar o radiales, lee estructura básica de una animación hero para aprender cómo estructurar el código de la animación hero, y detrás de escena para entender cómo Flutter realiza una animación hero.
Estructura básica de una animación hero
#- Usa dos widgets hero en diferentes rutas pero con tags coincidentes para implementar la animación.
- El Navigator gestiona una pila que contiene las rutas de la app.
- Hacer push de una ruta o pop de una ruta de la pila del Navigator activa la animación.
- El framework de Flutter calcula un tween de rectángulo,
RectTweenque define el límite del hero a medida que vuela desde la ruta de origen hacia la de destino. Durante su vuelo, el hero se mueve a un overlay de la aplicación, para que aparezca sobre ambas rutas.
Si el concepto de tweens o tweening es nuevo para ti, consulta el tutorial de Animaciones en Flutter.
Las animaciones hero se implementan utilizando dos widgets Hero:
uno describe el widget en la ruta de origen,
y el otro describe el widget en la ruta de destino.
Desde el punto de vista del usuario, el hero parece ser compartido, y
solo el programador necesita entender este detalle de implementación.
El código de la animación hero tiene la siguiente estructura:
- Define un widget Hero inicial, denominado hero de origen. El hero especifica su representación gráfica (típicamente una imagen), y un tag identificador, y se encuentra en el árbol de widgets actualmente mostrado según lo definido por la ruta de origen.
- Define un widget Hero final, denominado hero de destino. Este hero también especifica su representación gráfica, y el mismo tag que el hero de origen. Es esencial que ambos widgets hero se creen con el mismo tag, típicamente un objeto que representa los datos subyacentes. Para obtener los mejores resultados, los héroes deben tener árboles de widgets prácticamente idénticos.
- Crea una ruta que contenga el hero de destino. La ruta de destino define el árbol de widgets que existe al final de la animación.
- Activa la animación haciendo push de la ruta de destino en la pila del Navigator. Las operaciones de push y pop del Navigator activan una animación hero para cada par de héroes con tags coincidentes en las rutas de origen y destino.
Flutter calcula el tween que anima los límites del Hero desde el punto inicial hasta el punto final (interpolando tamaño y posición), y realiza la animación en un overlay.
La siguiente sección describe el proceso de Flutter con mayor detalle.
Detrás de escena
#A continuación se describe cómo Flutter realiza la transición de una ruta a otra.
Antes de la transición, el hero de origen espera en el árbol de widgets de la ruta de origen. La ruta de destino aún no existe, y el overlay está vacío.

Hacer push de una ruta al Navigator activa la animación.
En t=0.0, Flutter hace lo siguiente:
-
Calcula la ruta del hero de destino, fuera de pantalla, usando el movimiento curvo como se describe en la especificación de motion de Material. Flutter ahora sabe dónde termina el hero.
-
Coloca el hero de destino en el overlay, en la misma ubicación y tamaño que el hero de origen. Agregar un hero al overlay cambia su orden Z para que aparezca sobre todas las rutas.
Mueve el hero de origen fuera de la pantalla.
A medida que el hero vuela, sus límites rectangulares se animan usando
Tween<Rect>, especificado en la propiedad
createRectTween
del Hero.
Por defecto, Flutter utiliza una instancia de
MaterialRectArcTween, que anima las
esquinas opuestas del rectángulo a lo largo de una trayectoria curva.
(Consulta Animaciones hero radiales para ver un ejemplo
que utiliza una animación Tween diferente.)
Cuando el vuelo se completa:
-
Flutter mueve el widget hero desde el overlay hacia la ruta de destino. El overlay ahora está vacío.
-
El hero de destino aparece en su posición final en la ruta de destino.
El hero de origen se restaura a su ruta.
Hacer pop de la ruta realiza el mismo proceso, animando al hero de regreso a su tamaño y ubicación en la ruta de origen.
Clases esenciales
#Los ejemplos de esta guía utilizan las siguientes clases para implementar animaciones hero:
Hero-
El widget que vuela de la ruta de origen a la de destino. Define un Hero para la ruta de origen y otro para la ruta de destino, y asigna a cada uno el mismo tag. Flutter anima pares de héroes con tags coincidentes.
InkWell-
Especifica qué sucede al tocar el hero. El método
onTap()delInkWellconstruye la nueva ruta y la añade (hace push) a la pila delNavigator. Navigator-
El
Navigatorgestiona una pila de rutas. Hacer push o pop de una ruta en la pila delNavigatoractiva la animación. Route-
Especifica una pantalla o página. La mayoría de las apps, más allá de las más básicas, tienen múltiples rutas.
Animaciones hero estándar
#- Especifica una ruta usando
MaterialPageRoute,CupertinoPageRoute, o construye una ruta personalizada usandoPageRouteBuilder. Los ejemplos de esta sección utilizan MaterialPageRoute. - Cambia el tamaño de la imagen al final de la transición
envolviendo la imagen de destino en un
SizedBox. - Cambia la ubicación de la imagen colocando la imagen
de destino en un widget de layout. Estos ejemplos usan
Container.
Cada uno de los siguientes ejemplos demuestra el vuelo de una imagen desde una ruta hacia otra. Esta guía describe el primer ejemplo.
- hero_animation
-
Encapsula el código del hero en un widget personalizado
PhotoHero. Anima el movimiento del hero a lo largo de una trayectoria curva, como se describe en la especificación de motion de Material. - basic_hero_animation
-
Utiliza el widget hero directamente. Este ejemplo más básico, proporcionado para tu referencia, no se describe en esta guía.
¿Qué está pasando?
#Hacer volar una imagen de una ruta a otra es fácil de implementar
usando el widget hero de Flutter. Al utilizar MaterialPageRoute
para especificar la nueva ruta, la imagen vuela a lo largo de una trayectoria curva,
como describe la especificación de motion de Material Design.
Crea una nueva app de Flutter y actualízala usando los archivos de hero_animation.
Para ejecutar el ejemplo:
- Toca en la foto de la ruta de inicio para hacer volar la imagen hacia una nueva ruta que muestra la misma foto en una ubicación y escala diferentes.
- Regresa a la ruta anterior tocando la imagen, o usando el gesto del dispositivo para volver a la ruta anterior.
- Puedes ralentizar la transición aún más usando la propiedad
timeDilation.
Clase PhotoHero
#La clase personalizada PhotoHero mantiene el hero, y su tamaño, imagen y comportamiento al ser tocado. PhotoHero construye el siguiente árbol de widgets:

Aquí está el código:
class PhotoHero extends StatelessWidget {
const PhotoHero({
super.key,
required this.photo,
this.onTap,
required this.width,
});
final String photo;
final VoidCallback? onTap;
final double width;
@override
Widget build(BuildContext context) {
return SizedBox(
width: width,
child: Hero(
tag: photo,
child: Material(
color: Colors.transparent,
child: InkWell(
onTap: onTap,
child: Image.asset(
photo,
fit: BoxFit.contain,
),
),
),
),
);
}
}
Información clave:
- La ruta de inicio se añade (push) implícitamente por
MaterialAppcuando se proporcionaHeroAnimationcomo la propiedad home de la app. - Un
InkWellenvuelve la imagen, haciendo que sea sencillo agregar un gesto de toque tanto al hero de origen como al de destino. - Definir el widget Material con un color transparente permite que la imagen "sobresalga" del fondo a medida que vuela a su destino.
- El
SizedBoxespecifica el tamaño del hero al inicio y al final de la animación. - Establecer la propiedad
fitde la Image enBoxFit.contain, garantiza que la imagen sea lo más grande posible durante la transición sin cambiar su relación de aspecto.
Clase HeroAnimation
#La clase HeroAnimation crea los PhotoHeroes de origen y destino,
y configura la transición.
Aquí está el código:
class HeroAnimation extends StatelessWidget {
const HeroAnimation({super.key});
Widget build(BuildContext context) {
timeDilation = 5.0; // 1.0 means normal animation speed.
return Scaffold(
appBar: AppBar(
title: const Text('Basic Hero Animation'),
),
body: Center(
child: PhotoHero(
photo: 'images/flippers-alpha.png',
width: 300.0,
onTap: () {
Navigator.of(context).push(MaterialPageRoute<void>(
builder: (context) {
return Scaffold(
appBar: AppBar(
title: const Text('Flippers Page'),
),
body: Container(
// Set background to blue to emphasize that it's a new route.
color: Colors.lightBlueAccent,
padding: const EdgeInsets.all(16),
alignment: Alignment.topLeft,
child: PhotoHero(
photo: 'images/flippers-alpha.png',
width: 100.0,
onTap: () {
Navigator.of(context).pop();
},
),
),
);
}
));
},
),
),
);
}
}
Información clave:
- Cuando el usuario toca el
InkWellque contiene el hero de origen, el código crea la ruta de destino utilizandoMaterialPageRoute. Hacer push de la ruta de destino a la pila delNavigatoractiva la animación. - El
Containerposiciona alPhotoHeroen la esquina superior izquierda de la ruta de destino, debajo delAppBar. - El método
onTap()para elPhotoHerode destino hace pop de la pila delNavigator, activando la animación que hace volar alHerode regreso a la ruta original. - Usa la propiedad
timeDilationpara ralentizar la transición mientras depuras.
Animaciones hero radiales
#- Una transformación radial anima una forma circular para convertirla en una forma cuadrada.
- Una animación hero radial realiza una transformación radial mientras hace volar al hero de la ruta de origen a la ruta de destino.
- MaterialRectCenterArcTween define la animación tween.
- Construye la ruta de destino usando
PageRouteBuilder.
Hacer volar a un hero de una ruta a otra mientras se transforma
de una forma circular a una forma rectangular es un efecto elegante
que puedes implementar usando widgets Hero.
Para lograr esto, el código anima la intersección de
dos formas de recorte (clip): un círculo y un cuadrado.
A lo largo de la animación, el recorte circular (y la imagen)
se escala de minRadius a maxRadius, mientras que el recorte
cuadrado mantiene un tamaño constante. Al mismo tiempo,
la imagen vuela desde su posición en la ruta de origen hacia su
posición en la ruta de destino. Para ver ejemplos visuales
de esta transición, consulta Transformación radial
en la especificación de motion de Material.
Esta animación puede parecer compleja (y lo es), pero puedes personalizar el ejemplo proporcionado según tus necesidades. El trabajo pesado ya está hecho por ti.
Cada uno de los siguientes ejemplos demuestra una animación hero radial. Esta guía describe el primer ejemplo.
- radial_hero_animation
Una animación hero radial como se describe en la especificación de motion de Material.
- basic_radial_hero_animation
-
El ejemplo más simple de una animación hero radial. La ruta de destino no tiene Scaffold, Card, Column o Text. Este ejemplo básico, proporcionado para tu referencia, no se describe en esta guía.
- radial_hero_animation_animate
_rectclip -
Extiende radial_hero_animation animando también el tamaño del recorte rectangular. Este ejemplo más avanzado, proporcionado para tu referencia, no se describe en esta guía.
La animación hero radial implica la intersección de una forma redonda con
una forma cuadrada. Esto puede ser difícil de ver, incluso ralentizando
la animación con timeDilation, por lo que podrías considerar activar
la bandera debugPaintSizeEnabled
durante el desarrollo.
¿Qué está pasando?
#El siguiente diagrama muestra la imagen recortada al inicio
(t = 0.0) y al final (t = 1.0) de la animación.
El gradiente azul (que representa la imagen) indica dónde se intersectan
las formas de recorte. Al comienzo de la transición,
el resultado de la intersección es un recorte circular (ClipOval).
Durante la transformación, el ClipOval se escala de minRadius
a maxRadius mientras que el ClipRect
mantiene un tamaño constante.
Al final de la transición, la intersección de los recortes circular y
rectangular produce un rectángulo del mismo tamaño que el widget hero.
En otras palabras, al final de la transición la imagen ya no está
recortada.
Crea una nueva app de Flutter y actualízala usando los archivos del directorio de GitHub radial_hero_animation.
Para ejecutar el ejemplo:
- Toca en una de las tres miniaturas circulares para animar la imagen hacia un cuadrado más grande posicionado en el medio de una nueva ruta que oculta la ruta original.
- Regresa a la ruta anterior tocando la imagen, o usando el gesto del dispositivo para volver a la ruta anterior.
- Puedes ralentizar la transición aún más usando la propiedad
timeDilation.
Clase Photo
#La clase Photo construye el árbol de widgets que contiene la imagen:
class Photo extends StatelessWidget {
const Photo({super.key, required this.photo, this.color, this.onTap});
final String photo;
final Color? color;
final VoidCallback onTap;
Widget build(BuildContext context) {
return Material(
// Slightly opaque color appears where the image has transparency.
color: Theme.of(context).primaryColor.withValues(alpha: 0.25),
child: InkWell(
onTap: onTap,
child: Image.asset(
photo,
fit: BoxFit.contain,
),
),
);
}
}
Información clave:
- El
InkWellcaptura el gesto de toque. La función que lo llama pasa la funciónonTap()al constructor dePhoto. - Durante el vuelo, el
InkWelldibuja su efecto splash sobre su primer ancestro Material. - El widget Material tiene un color ligeramente opaco, por lo que las partes transparentes de la imagen se renderizan con color. Esto asegura que la transición de círculo a cuadrado sea fácil de ver, incluso para imágenes con transparencia.
- La clase
Photono incluye alHeroen su árbol de widgets. Para que la animación funcione, el hero envuelve al widgetRadialExpansion.
Clase RadialExpansion
#El widget RadialExpansion, el núcleo de la demostración, construye el
árbol de widgets que recorta la imagen durante la transición.
La forma recortada resulta de la intersección de un recorte circular
(que crece durante el vuelo),
con un recorte rectangular (que mantiene un tamaño constante durante todo el proceso).
Para hacer esto, construye el siguiente árbol de widgets:
Aquí está el código:
class RadialExpansion extends StatelessWidget {
const RadialExpansion({
super.key,
required this.maxRadius,
this.child,
}) : clipRectSize = 2.0 * (maxRadius / math.sqrt2);
final double maxRadius;
final double clipRectSize;
final Widget? child;
@override
Widget build(BuildContext context) {
return ClipOval(
child: Center(
child: SizedBox(
width: clipRectSize,
height: clipRectSize,
child: ClipRect(
child: child, // Photo
),
),
),
);
}
}
Información clave:
El hero envuelve al widget
RadialExpansion.-
A medida que el hero vuela, su tamaño cambia y, debido a que limita el tamaño de su hijo, el widget
RadialExpansioncambia de tamaño para coincidir. La animación
RadialExpansionse crea mediante dos recortes superpuestos.-
El ejemplo define la interpolación tweening utilizando
MaterialRectCenterArcTween. La trayectoria de vuelo por defecto para una animación hero interpola los tweens usando las esquinas de los héroes. Este enfoque afecta la relación de aspecto del hero durante la transformación radial, por lo que la nueva trayectoria de vuelo utilizaMaterialRectCenterArcTweenpara interpolar los tweens usando el punto central de cada hero.Aquí está el código:
dartstatic RectTween _createRectTween(Rect? begin, Rect? end) { return MaterialRectCenterArcTween(begin: begin, end: end); }La trayectoria de vuelo del hero sigue siguiendo un arco, pero la relación de aspecto de la imagen permanece constante.
A menos que se indique lo contrario, la documentación de este sitio refleja Flutter 3.44.0. Página actualizada por última vez el 2026-05-05. Ver código fuente oreportar un problema.