Q&A
How to use the Hero class in Flutter
Overview
When navigating between screens, a Hero animation visually connects a widget on the first screen to its counterpart on the second, animating size and position so the element seems to morph and move across the transition. This creates a polished, continuous feel. The mechanism is entirely declarative: matching tags tell Flutter which widgets correspond.
graph LR
A["Screen A: Hero(tag: 'x', child: image)"] -->|navigate| B["Screen B: Hero(tag: 'x', child: image)"]
A -.Flutter matches same tag.-> C[Animates element flying A → B]
style C fill:#1e1b4b,color:#fff
Basic Usage
Wrap the widget on both screens in a Hero with an identical tag.
Source screen:
GestureDetector(
onTap: () => Navigator.push(
context,
MaterialPageRoute(builder: (_) => DetailScreen()),
),
child: Hero(
tag: "profile-photo", // must match the destination
child: Image.asset("assets/avatar.png", width: 60, height: 60),
),
)
Destination screen:
Hero(
tag: "profile-photo", // SAME tag → animates between them
child: Image.asset("assets/avatar.png", width: 300, height: 300),
)
On navigation, Flutter sees the matching tags and animates the image flying and growing from 60×60 on screen A to 300×300 on screen B - and reverses it on back-navigation. No animation code required.
The Key Rule: Unique, Matching Tags
- The
tagmust be identical on both screens for the pair you want to connect. - The
tagmust be unique within a single screen - twoHeros with the same tag on the same route throw an error. - For lists, give each item a unique tag (e.g. include the item's id):
Hero(tag: "item-${product.id}", child: ProductImage(product))
Customizing the Flight
You can control how the hero looks mid-flight with flightShuttleBuilder:
Hero(
tag: "logo",
flightShuttleBuilder: (flightContext, animation, direction, fromContext, toContext) {
// return a custom widget shown during the transition
return ScaleTransition(scale: animation, child: const FlutterLogo());
},
child: const FlutterLogo(size: 50),
)
createRectTween lets you customize the flight path (e.g. a curved arc instead of a straight line).
Common Use Cases
- Tapping a thumbnail that expands into a full-screen image.
- A profile avatar growing into a profile detail page.
- A list/grid card morphing into its detail view.
- A logo animating from a splash screen to the home screen.
Notes and Constraints
- The two heroes don't have to be identical widgets - Flutter cross-fades different children of the same tag - but matching content looks best.
- Heroes animate during
Navigatorroute transitions; they don't apply to in-page state changes (use other animations there). - Avoid wrapping very large/complex subtrees; animate a focused element.
Why This Matters in Interviews
Flutter interviews use Hero to test navigation and animation knowledge. The essentials: wrap source and destination widgets in Hero with the same tag, tags must be unique per screen, and Flutter auto-animates the shared element during route transitions (declarative - no manual animation). Knowing the list pattern (unique tag per item via id), flightShuttleBuilder for custom flights, and that it ties to Navigator transitions shows depth.
Common Pitfalls
- Duplicate tags on the same screen → runtime error.
- Mismatched tags between screens → no animation occurs.
- Reusing the same constant tag for every item in a list (must be unique).
- Expecting Hero to animate non-navigation state changes.
- Wrapping huge subtrees, causing janky or odd transitions.
References
- Flutter Hero animations guide: https://docs.flutter.dev/ui/animations/hero-animations
HeroAPI: https://api.flutter.dev/flutter/widgets/Hero-class.html