Let’s talk about hero animations in flutter app development, but first if you are new and want a complete setup and want to build your first app instantly, then click here, now let’s jump into hero animations in flutter app, what they really are, their role, and usage in flutter apps. So the first thing that would come to your mind will be, what is a hero animation in a flutter app? Does dart language really provides us with some pre build animations which we can use in our flutter app? Let’s find out:
Introduction
A hero animation is simply a flying animation which takes place during transition of flutter app screens, when we navigate from one screen to another screen in flutter app. That’s the time where hero animations works.
Demo
Implementation
Let’s see how we can use our hero animation in our flutter app. For that, let’s look at the code given below:
Hero( tag: 'test hero tag', child: Text('Hero animated text') )
As you can see we have wrapper a text widget inside a hero class. The hero class is used to do the hero animations, it has a tag constructor in which we pass a unique value. It identifies a particular hero, from where a hero comes or where to. Simple way is that if you want to do a hero animation between two widgets then just wrap both widgets in a hero class and use a same tag e.g. tag: ‘unique tag’. Now if you want hero animation to take place between both of them then just put them in different screens and navigate from the screen where one of these two widgets are present and navigate to the other screen which has the other widget. Then you will see a hero animation during the transition in flutter app. Enough of the theory thing, let’s understand it with a flutter app code:
Gesture Detector
As you can see in above code, there is no triggering from one page to another. Let’s see how we can make our text clickable:
GestureDetector( onTap:(){} child: Text('Hero animated text') )
As you can see, we have wrapped our text widget with gesture detector class. If you want to make text widget, container widget or any widget clickable then you just need to wrap it with the gesture detector widget. The on tap constructor is used to define which function will that widget perform after it is clicked. We will use it to navigate to the other screen where our other hero widget is defined, so we can see a hero animation in our flutter app. Let’s see how:
Explanation
For that, we have to use two screens:
- First Screen
- Second Screen
First Screen
Scaffold(
body:
Hero( tag: 'just a tag', child: GestureDetector( onTap: () { Navigator.of(context).push(PageRouteBuilder( transitionDuration: Duration(milliseconds: 600), reverseTransitionDuration Duration(milliseconds: 200), pageBuilder: (context, animation, secondaryAnimation) => HeroAnimationPage( ))); }, child: Text('Perform hero animation')))
Second Screen
Hero(
tag: ‘just a tag’,
child: Text(‘Hero animation performed’))
In the second screen, we just need to define our target hero widget like this, flutter will do the rest for us. Now when you click the text mentioned above in the first screen then you will be navigated to this screen along with a beautiful flutter hero animation. Now, that you have understand how it works. Let’s implement a beautiful example as mentioned and if you implement it then you will see a beautiful animation takes place during page transitions in your flutter app.
Mentioned Design Example
import 'package:flutter/material.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Grid View', debugShowCheckedModeBanner: false, home: HomePage(), ); } } class HomePage extends StatelessWidget { List colors = [ Colors.blue.shade100, Colors.blue.shade200, Colors.blue.shade300, Colors.blue.shade400, Colors.blue.shade500, Colors.blue.shade600, Colors.blue.shade700, Colors.blue.shade800, Colors.blue.shade500, Colors.blue.shade600, Colors.blue.shade700, Colors.blue.shade800, Colors.blue.shade900, ]; @override Widget build(BuildContext context) { return SafeArea( child: Scaffold( body: Center( child: Column( children: [ Padding( padding: const EdgeInsets.all(20).copyWith(top: 40), child: Text( 'Hero Animation', textAlign: TextAlign.center, style: TextStyle(shadows: [ Shadow( blurRadius: 3, offset: Offset(2, 2), color: Colors.grey.withOpacity(.6)) ], fontSize: 28, fontWeight: FontWeight.bold, color: Colors.blue), ), ), Expanded( child: ListView.builder( shrinkWrap: true, itemCount: colors.length, itemBuilder: (context, index) { return Hero( tag: index.toString(), child: GestureDetector( onTap: () { Navigator.of(context).push(PageRouteBuilder( transitionDuration: Duration(milliseconds: 600), reverseTransitionDuration: Duration(milliseconds: 200), pageBuilder: (context, animation, secondaryAnimation) => HeroAnimationPage( index: index.toString(), color: colors[index], ))); }, child: Container( height: 50, width: double.infinity, alignment: Alignment.center, margin: EdgeInsets.all(10), decoration: BoxDecoration( color: colors[index], boxShadow: [ BoxShadow( blurRadius: 5, spreadRadius: 0, offset: Offset(4, 4), color: Colors.black45) ], borderRadius: BorderRadius.circular(100)), child: Text( 'Let\'s Animate $index', style: TextStyle( decoration: TextDecoration.none, color: Colors.white, fontWeight: FontWeight.bold), ), ), ), ); }), ), ], )), )); } } class HeroAnimationPage extends StatelessWidget { final String index; final Color color; const HeroAnimationPage({Key? key, required this.index, required this.color}) : super(key: key); @override Widget build(BuildContext context) { return SafeArea( child: Scaffold( body: Column( children: [ Hero( tag: index, child: Container( height: 200, width: double.infinity, alignment: Alignment.center, decoration: BoxDecoration( color: color, boxShadow: [ BoxShadow( blurRadius: 10, spreadRadius: 5, color: Colors.black54) ], borderRadius: BorderRadius.only( bottomLeft: Radius.circular(20), bottomRight: Radius.circular(20))), child: Text( 'Animation $index done', style: TextStyle( decoration: TextDecoration.none, color: Colors.white, fontWeight: FontWeight.bold, fontSize: 24), ), ), ), SizedBox( height: 50, ), Padding( padding: const EdgeInsets.all(20), child: Text( 'This is how a hero animation looks like, it takes place during the transition between pages', textAlign: TextAlign.center, style: TextStyle(shadows: [ Shadow( blurRadius: 3, offset: Offset(2, 2), color: Colors.grey.withOpacity(.6)) ], fontSize: 28, fontWeight: FontWeight.bold, color: Colors.blue), ), ) ], ), )); } }
Note:
That’s all for this article, hope you enjoyed it and have learnt a lot from it. Implement it in your code and share your experience with us. We would love to see how you have used it in your flutter app. We would be looking forward for your response. Hope to see you in our next articles in which we will dig deep into other amazing widgets. Thanks for reading.