Skip to content

Expert · Animations and performance · topic 37 of 50 · 25 min

Hero, page transitions and Lottie or Rive

Explanation

A Hero animation flies a shared element, such as a product image, from one screen to the next when both use the same tag. PageRouteBuilder lets you design custom page transitions. For complex, designer-made animations, use the lottie or rive packages instead of coding them. Respect the user's reduce-motion setting with MediaQuery, and do not over-animate.

Hero: shared element transitions

When a user taps a product photo in a grid and the details page opens, a Hero animation makes the photo smoothly fly and grow from its grid position to its place on the new page. This visual link tells the user "this is the same item, now bigger". Wrap the widget in Hero on both screens with the same, unique tag; Flutter does the rest during navigation.

dart
// In the grid (first screen):
Hero(
  tag: 'product-${product.id}',
  child: Image.network(product.imageUrl, fit: BoxFit.cover),
)

// On the details page (second screen):
Hero(
  tag: 'product-${product.id}',
  child: Image.network(product.imageUrl, height: 300, width: double.infinity, fit: BoxFit.cover),
)
Tags must match between screens and be unique on each screen.
Careful: Duplicate Hero tags on the same screen (for example two grid items with the tag "product") cause an error: "There are multiple heroes that share the same tag within a subtree". Include the item's id in the tag.

Hero works with Navigator and with go_router.

Custom page transitions

dart
Route<void> slideUpRoute(Widget page) => PageRouteBuilder(
      transitionDuration: const Duration(milliseconds: 300),
      pageBuilder: (context, animation, secondaryAnimation) => page,
      transitionsBuilder: (context, animation, secondaryAnimation, child) {
        final offset = Tween(begin: const Offset(0, 1), end: Offset.zero)
            .chain(CurveTween(curve: Curves.easeOutCubic))
            .animate(animation);
        return SlideTransition(position: offset, child: child);
      },
    );

// Navigator.push(context, slideUpRoute(const FiltersPage()));
The new page slides up from the bottom. go_router also supports custom transitions via CustomTransitionPage.

Use custom transitions sparingly and consistently. Platform-default transitions (from MaterialPageRoute) already feel right on Android and iOS; a custom transition is best kept for special flows like a filter sheet or an onboarding sequence.

Lottie and Rive

Some animations, like a delivery scooter riding across the screen, a celebratory confetti burst or an animated empty-state illustration, are much easier for a designer to create than for a developer to code. Lottie plays animations exported as JSON from After Effects (via the Bodymovin plugin); Rive is a design tool whose interactive animations can react to app state through state machines. Both have Flutter packages on pub.dev.

dart
// pubspec: lottie package; asset: assets/anim/success.json
Lottie.asset('assets/anim/success.json', width: 160, repeat: false)
A designer-made success animation in one line. Keep files small; large animations slow down loading.

Respecting reduced motion

Some users turn on "remove animations" or reduced motion in system settings because motion makes them dizzy or distracted. Flutter exposes this as MediaQuery.disableAnimationsOf(context). When it is true, shorten or skip decorative animations, keeping only essential feedback.

dart
final reduce = MediaQuery.disableAnimationsOf(context);
final duration = reduce ? Duration.zero : const Duration(milliseconds: 300);
Honour the system setting for decorative motion.
Think of it like this: A Hero animation is like a person walking from the waiting room into the doctor's cabin: you see them move from one room to the next, so you know it is the same person. Without it, they would vanish from one room and appear in the other, which is confusing.

Common mistakes

  • Duplicate Hero tags on one screen.
  • Hero children that look very different on the two screens (text styles jumping): keep them visually similar.
  • Heavy Lottie files (several MB) on the home screen: slow start-up.
  • Animations everywhere, ignoring reduced-motion settings.

Need help?

Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.

Try:

Watch the lesson

Hero, page transitions and Lottie or Rive · 1/6

Hero

A Hero animation flies a shared element from one screen to the next.

Prefer a video by a teacher? Find free videos on “flutter hero animation page route builder custom transition lottie rive” on YouTube ↗

In real life: Product photo to details page

A fashion app's grid shows small product photos. Tapping one flies the photo up into the large image on the details page using a Hero with the tag "product-123". After a successful order, a short Lottie confetti animation plays once, unless the user has reduced motion turned on, in which case a simple tick icon appears instead.

Practice (0/3 done)

Task 1 · Question

What makes two Hero widgets on different screens animate together?

Task 2 · Question

A grid uses Hero(tag: "photo") for every item. What happens?

Task 3 · Practice

Add Hero transitions between a product grid and a details page using tags with the product id. Add a custom slide-up transition for a filters page with PageRouteBuilder. Finally, check MediaQuery.disableAnimationsOf and skip the custom transition duration when it is true (test by enabling "Remove animations" in the phone's accessibility settings).

Quick quiz

Question 1

1.What is a Hero animation for?

Question 2

2.Which package plays After Effects animations exported as JSON?

Question 3

3.How do you detect that the user prefers reduced motion?

Question 4

4.Which widget builds a fully custom page transition?

Read more (free)

Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.

What is a Hero animation for?

Answer: Visually linking the same element across two screens during navigation

Shared element transition.

Which package plays After Effects animations exported as JSON?

Answer: lottie

Lottie files are JSON.

How do you detect that the user prefers reduced motion?

Answer: MediaQuery.disableAnimationsOf(context)

Flutter exposes the accessibility setting.

Which widget builds a fully custom page transition?

Answer: PageRouteBuilder

You provide pageBuilder and transitionsBuilder.

What does @media (prefers-reduced-motion: reduce) detect?Related

Answer: A user who asked their device for less motion

It matches when the user has turned on a reduce-motion setting.

From Transitions and animations

Which call loops an animation back and forth?Related

Answer: repeat(reverse: true)

repeat with reverse goes 0 to 1 to 0.

From Explicit animations

What two parameters do implicit animation widgets need besides their normal properties?Related

Answer: duration (and optionally curve)

They handle the rest.

From Implicit animations

Why prefer MediaQuery.sizeOf(context) over MediaQuery.of(context).size?Related

Answer: It rebuilds only when the size changes

Fewer unnecessary rebuilds.

From Responsive and adaptive design

Pass the quiz (60% or more) or mark this topic as done when you are ready.

Your progress is saved on this device only.

Next steps

  1. 1 more topic in “Animations and performance” before its exam: Performance.
  2. Module 9 exam: Animations and performance · 12 questions · 25 min, without help. 4 topics of this module still to finish first.
  3. Then the next module, Responsive design and testing. 50 topics left in the course before the final exam.

← Previous: Explicit animations