It’s often helpful to guide users through our apps as they navigate from screento screen. A common technique to lead users through an app is to animate aWidget from one screen to the next. This creates a visual anchor connectingthe two screens.

How can we animate a Widget from one screen to the next with Flutter? Using theHero Widget!

Directions

  • Create two screens showing the same image
  • Add a Hero Widget to the first screen
  • Add a Hero Widget to the second screen

1. Create two screens showing the same image

In this example, we’ll display the same image on both screens. We’ll want toanimate the image from the first screen to the second screen when the user tapson the image. For now, we’ll create the visual structure, and handle animationsin the next steps!

Note: This example builds upon theNavigate to a new screen and backand Handling Taps recipes.

  1. class MainScreen extends StatelessWidget {
  2. @override
  3. Widget build(BuildContext context) {
  4. return Scaffold(
  5. appBar: AppBar(
  6. title: Text('Main Screen'),
  7. ),
  8. body: GestureDetector(
  9. onTap: () {
  10. Navigator.push(context, MaterialPageRoute(builder: (_) {
  11. return DetailScreen();
  12. }));
  13. },
  14. child: Image.network(
  15. 'https://picsum.photos/250?image=9',
  16. ),
  17. ),
  18. );
  19. }
  20. }
  21. class DetailScreen extends StatelessWidget {
  22. @override
  23. Widget build(BuildContext context) {
  24. return Scaffold(
  25. body: GestureDetector(
  26. onTap: () {
  27. Navigator.pop(context);
  28. },
  29. child: Center(
  30. child: Image.network(
  31. 'https://picsum.photos/250?image=9',
  32. ),
  33. ),
  34. ),
  35. );
  36. }
  37. }

2. Add a Hero Widget to the first screen

In order to connect the two screens together with an animation, we need to wrapthe Image Widget on both screens in a Hero Widget. The Hero Widgetrequires two arguments:

  • tag: An object that identifies the Hero. It must be the same on both screens.
  • child: The Widget we want to animate across screens.
  1. Hero(
  2. tag: 'imageHero',
  3. child: Image.network(
  4. 'https://picsum.photos/250?image=9',
  5. ),
  6. );

3. Add a Hero Widget to the second screen

To complete the connection with the first screen, we need to wrap the Imageon the second screen with a Hero Widget as well! It must use the same tagas the first screen.

After you apply the Hero Widget to the second screen, the animation betweenscreens will work!

  1. Hero(
  2. tag: 'imageHero',
  3. child: Image.network(
  4. 'https://picsum.photos/250?image=9',
  5. ),
  6. );

Note: this code is identical to what we had on the first screen! In general, youcould create a reusable Widget instead of repeating code, but for this example,we’ll duplicate the code for demonstration purposes.

Complete example

  1. import 'package:flutter/material.dart';
  2. void main() => runApp(HeroApp());
  3. class HeroApp extends StatelessWidget {
  4. @override
  5. Widget build(BuildContext context) {
  6. return MaterialApp(
  7. title: 'Transition Demo',
  8. home: MainScreen(),
  9. );
  10. }
  11. }
  12. class MainScreen extends StatelessWidget {
  13. @override
  14. Widget build(BuildContext context) {
  15. return Scaffold(
  16. appBar: AppBar(
  17. title: Text('Main Screen'),
  18. ),
  19. body: GestureDetector(
  20. child: Hero(
  21. tag: 'imageHero',
  22. child: Image.network(
  23. 'https://picsum.photos/250?image=9',
  24. ),
  25. ),
  26. onTap: () {
  27. Navigator.push(context, MaterialPageRoute(builder: (_) {
  28. return DetailScreen();
  29. }));
  30. },
  31. ),
  32. );
  33. }
  34. }
  35. class DetailScreen extends StatelessWidget {
  36. @override
  37. Widget build(BuildContext context) {
  38. return Scaffold(
  39. body: GestureDetector(
  40. child: Center(
  41. child: Hero(
  42. tag: 'imageHero',
  43. child: Image.network(
  44. 'https://picsum.photos/250?image=9',
  45. ),
  46. ),
  47. ),
  48. onTap: () {
  49. Navigator.pop(context);
  50. },
  51. ),
  52. );
  53. }
  54. }

Hero Demo