Integrating Hero Flutter Animation

In this flutter example, We will integrate flutter hero animation between two screens. We will create this flutter hero animation with the help of Hero Widget in this flutter tutorial.

Hero animation means flying one element from one screen to another screen when new screen launches. To apply this animation, We need to add hero widget as parent widget of element which will be animated.

Flutter Hero animation works in both directions means when you go to new screen or back to old screen. In both scenarios, Hero animation is applied to elements.

We will create two screens list and details. First we will apply hero animation to images in list and details screens. Then we will apply this to titles in both screens. You can also check out same animation to integrate in native android app using Shared Element Transitions.

 

Add routes in material app widget

MaterialApp(
    onGenerateRoute: generateRoute,
);
 
Route<dynamic> generateRoute(RouteSettings settings) {
final args = settings.arguments;

switch (settings.name) {
    case ‘/ListScreen’:
        return MaterialPageRoute(builder: (_) => ListPage());
    case ‘/DetailsScreen’:
        return MaterialPageRoute(
            builder: (_) => DetailsPage(
                country: args,
            ),
        );
    default:
        return null;
}
}

 
 

Add Hero Widget For Image Flutter Animation

First we need to add hero widget as parent widget of image in both list and details screens. So animation will be displayed for this two images when screen will be changed.

Hero(
    child: Image.asset(country.imagePath,
    fit: BoxFit.cover))
 
 

Add Hero Widget For Title Flutter Animation

After wrapping both text widgets in Hero widget, You can see title transition animation between list and details screens when you go to another screen.

Hero(
    child: Text(widget.country.title,
    style: TextStyle(
    fontWeight: FontWeight.bold,
    fontSize: 25,
    color: Colors.white))))
 
 

Assign same tag for both images

In List Screen:

Hero(
    tag: country.imagePath,
    transitionOnUserGestures: true,
    child: Image.asset(country.imagePath,
    fit: BoxFit.cover))
 

In Details Screen:

Hero(
    tag: widget.country.imagePath,
    transitionOnUserGestures: true,
    child: Image.asset(
    widget.country.imagePath,
    fit: BoxFit.cover)))
 
 

Assign same tag for both titles

In List Screen:

Hero(
    tag: country.title,
    transitionOnUserGestures: true,
    child: Text(country.title,
    style: TextStyle(
    fontWeight: FontWeight.bold,
    fontSize: 25,
    color: Colors.white,
    shadows: [
        Shadow(
            blurRadius: 3.0,
            color: Colors.black12,
            offset: Offset(3.0, 3.0),
        ),
    ],
))
 

In Details Screen:

Hero(
    tag: widget.country.title,
    transitionOnUserGestures: true,
    child: Text(widget.country.title,
    style: TextStyle(
    fontWeight: FontWeight.bold,
    fontSize: 25,
    color: Colors.white))))
 
 

Final Code

main.dart

import 'package:flutter/material.dart';
import 'details.dart';
import 'list.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: ListPage(),
      onGenerateRoute: generateRoute,
    );
  }

  Route<dynamic> generateRoute(RouteSettings settings) {
    final args = settings.arguments;

    switch (settings.name) {
      case '/ListScreen':
        return MaterialPageRoute(builder: (_) => ListPage());
      case '/DetailsScreen':
        return MaterialPageRoute(
          builder: (_) => DetailsPage(
            country: args,
          ),
        );
      default:
        return null;
    }
  }
}
 

country.dart

class Country{

  String title;
  String imagePath;
  String desc;

  Country(this.title, this.imagePath, this.desc);

}
 

list.dart

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'country.dart';

class ListPage extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    // TODO: implement createState
    return ListPageState();
  }
}

class ListPageState extends State<ListPage> {
  Country usa = Country("USA", "images/usa.jpg",
      "The U.S. is a country of 50 states covering a vast swath of North America, with Alaska in the northwest and Hawaii extending the nation’s presence into the Pacific Ocean. Major Atlantic Coast cities are New York, a global finance and culture center, and capital Washington, DC. Midwestern metropolis Chicago is known for influential architecture and on the west coast, Los Angeles' Hollywood is famed for filmmaking.");
  Country england = Country("England", "images/england.jpg",
      "England is a country that is part of the United Kingdom. It shares land borders with Wales to its west and Scotland to its north. The Irish Sea lies northwest of England and the Celtic Sea to the southwest. England is separated from continental Europe by the North Sea to the east and the English Channel to the south.");
  Country france = Country("France", "images/france.jpg",
      "France, in Western Europe, encompasses medieval cities, alpine villages and Mediterranean beaches. Paris, its capital, is famed for its fashion houses, classical art museums including the Louvre and monuments like the Eiffel Tower. The country is also renowned for its wines and sophisticated cuisine. Lascaux’s ancient cave drawings, Lyon’s Roman theater and the vast Palace of Versailles attest to its rich history.");
  Country russia = Country("Russia", "images/russia.jpg",
      "Russia, or the Russian Federation, is a transcontinental country located in Eastern Europe and Northern Asia.");
  Country canada = Country("Canada", "images/canada.jpg",
      "Canada is a country in the northern part of North America. Its ten provinces and three territories extend from the Atlantic to the Pacific and northward into the Arctic Ocean, covering 9.98 million square kilometres, making it the world's second-largest country by total area.");

  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: Container(
          color: Colors.white,
          child: GridView.count(
            crossAxisCount: 2,
            childAspectRatio: 1.3,
            padding: const EdgeInsets.all(5.0),
            mainAxisSpacing: 5.0,
            crossAxisSpacing: 5.0,
            children: <Country>[usa, england, france, russia, canada]
                .map((Country country) {
              return GestureDetector(
                  child: Card(
                    clipBehavior: Clip.antiAliasWithSaveLayer,
                    shape: RoundedRectangleBorder(
                      borderRadius: BorderRadius.circular(10.0),
                    ),
                    child: Stack(fit: StackFit.expand, children: <Widget>[
                      Hero(
                          tag: country.imagePath,
                          transitionOnUserGestures: true,
                          child: Image.asset(country.imagePath,
                              fit: BoxFit.cover)),
                      Container(
                          margin: EdgeInsets.only(left: 10, bottom: 10),
                          alignment: Alignment.bottomLeft,
                          child: Hero(
                            tag: country.title,
                            transitionOnUserGestures: true,
                            child: Text(country.title,
                                style: TextStyle(
                                  fontWeight: FontWeight.bold,
                                  fontSize: 25,
                                  color: Colors.white,
                                  shadows: [
                                    Shadow(
                                      blurRadius: 3.0,
                                      color: Colors.black12,
                                      offset: Offset(3.0, 3.0),
                                    ),
                                  ],
                                )),
                          ))
                    ]),
                  ),
                  onTap: () => Navigator.pushNamed(context, "/DetailsScreen",
                      arguments: country));
            }).toList(),
          )),
    );
  }
}

 

details.dart

import 'package:flutter/material.dart';
import 'country.dart';

class DetailsPage extends StatefulWidget {
  Country country;

  DetailsPage({this.country});

  @override
  State<StatefulWidget> createState() {
    // TODO: implement createState
    return DetailsPageState();
  }
}

class DetailsPageState extends State<DetailsPage> {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return SafeArea(
      child: Scaffold(
        appBar: AppBar(
            title: Hero(
                tag: widget.country.title,
                transitionOnUserGestures: true,
                child: Text(widget.country.title,
                    style: TextStyle(
                        fontWeight: FontWeight.bold,
                        fontSize: 25,
                        color: Colors.white)))),
        body: Container(
          child: Column(
            children: <Widget>[
              Container(
                  height: 300,
                  child: Hero(
                      tag: widget.country.imagePath,
                      transitionOnUserGestures: true,
                      child: Image.asset(
                        widget.country.imagePath,
                        fit: BoxFit.cover,
                      ))),
              Container(
                  margin: EdgeInsets.all(10),
                  child:
                      Text(widget.country.desc, style: TextStyle(fontSize: 18)))
            ],
          ),
        ),
      ),
    );
  }
}

 
 
 
flutter animation
 
 

Leave a Reply