Flutter code recipe for Hero animation
Hero animation is a useful transition when items are listed with small icons. Tapping on icons can open in another page with enlarged icon widget.
Recipe: Hero animation to transition a list icon into an enlarged view on another detail page.
Focus Widget: Hero Widget
Hero(
tag: 'hero-rectangle',
child: _blueDetailRectangle(),
),
Goal: Animate and enlarge list item icon using Hero
widget. Tapping on a list item icon, opens up the item in another page with enlarged icon.
Lets's go!
We need these things to accomplish our goal.
- List item along with Icon: I'll be using a rectangle widget for icon.
Icon widget in list item at first page:
Widget _blueIconRectangle() {
return Container(
width: 50,
height: 50,
color: Colors.blue,
);
}
Hero
widget in list:
Widget buildWidget(BuildContext context) {
return Center(
...
child: Hero(
tag: 'hero-rectangle',
child: _blueIconRectangle(),
),
onTap: () => _gotoDetailsPage(context),
...
}
- Enlarged icon to display on the second page.
Widget _blueDetailRectangle() {
return Container(
width: 200,
height: 200,
color: Colors.blue,
);
}
Using enlarged icon in second page:
void _gotoDetailsPage(BuildContext context) {
Navigator.of(context).push(MaterialPageRoute(
builder: (ctx) => Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Hero(
tag: 'hero-rectangle',
child: _blueDetailRectangle(),
),
Text(
'This is where you can see details about the list item tapped at previous page.'),
],
),
),
),
));
}
Notice that Navigator.of(context).push()
is needed to navigate to second page from first page
using the same tag.
- Making sure both widgets in step #1 and step #2 have same tag.
Hero transitions use the same tag to identify the start and destination widgets.
Complete example code
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.green,
),
home: HeroAnimationRecipe(title: 'Hero Animation'),
);
}
}
class HeroAnimationRecipe extends StatefulWidget {
HeroAnimationRecipe({Key key, this.title}) : super(key: key);
final String title;
@override
_HeroAnimationRecipeState createState() => _HeroAnimationRecipeState();
}
class _HeroAnimationRecipeState extends State<HeroAnimationRecipe> {
Widget _blueIconRectangle() {
return Container(
width: 50,
height: 50,
color: Colors.blue,
);
}
Widget _blueDetailRectangle() {
return Container(
width: 200,
height: 200,
color: Colors.blue,
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: buildDemoWidget(context),
);
}
Widget buildDemoWidget(BuildContext context) {
return Center(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
SizedBox(
height: 20.0,
),
ListTile(
leading: GestureDetector(
child: Hero(
tag: 'hero-rectangle',
child: _blueIconRectangle(),
),
onTap: () => _gotoDetailsPage(context),
),
title: Text('Tap on the icon to view hero animation transition.'),
),
],
),
);
}
void _gotoDetailsPage(BuildContext context) {
Navigator.of(context).push(MaterialPageRoute(
builder: (ctx) => Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Hero(
tag: 'hero-rectangle',
child: _blueDetailRectangle(),
),
Text(
'This is where you can see details about the list item tapped at previous page.'),
],
),
),
),
));
}
}
Source code repo:
Recipe source code is available here
References:
Liked the article ? Please let me know in the comments below what other topics you would like me to write.