系列文章
- Flutter 旋转动画 — RotationTransition
- Flutter 平移动画 — 4种实现方式
- Flutter 淡入淡出与逐渐出现动画
- Flutter 尺寸缩放、形状、颜色、阴影变换动画
- Flutter 列表Item动画 — AnimatedList实现Item左进左出、淡入淡出
- Flutter Hero 实现共享元素转场动画
- Flutter Hero 实现径向变换动画 — 圆形变成矩形的转场动画
- Flutter 自定义动画 — 数字递增动画和文字逐行逐字出现或消失动画
1 动画效果
2 Hero介绍
Hero 是Flutter提供的一个可以实现子Widget在页面切换时带有飞行效果的Widget,可实现元素共享动画效果。
3 未使用Hero时的页面切换
列表页面
class ListPage extends StatefulWidget {
const ListPage({Key? key}) : super(key: key);
@override
State<StatefulWidget> createState() => _ListPageState();
}
class _ListPageState extends State<ListPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('列表页'), centerTitle: true),
body: GridView.count(
crossAxisCount: 2,
children: List.generate(10, _buildItem),
),
);
}
Widget _buildItem(int index) {
return CupertinoButton(
padding: EdgeInsets.zero,
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => DetailPage(index: index)),
);
},
child: _buildImageWidget(index),
);
}
// 列表页的Image size是120
Widget _buildImageWidget(int index) {
return const FlutterLogo(size: 120);
}
}
详情页面
class DetailPage extends StatefulWidget {
final int index;
const DetailPage({Key? key, required this.index}) : super(key: key);
@override
State<StatefulWidget> createState() => _DetailPageState();
}
class _DetailPageState extends State<DetailPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('详情页'), centerTitle: true),
body: SizedBox(
width: double.infinity,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
const SizedBox(height: 12),
_buildImageWidget(widget.index),
const SizedBox(height: 12),
Text(
' ${widget.index} :登高(作者:杜甫)',
style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 20),
),
const SizedBox(height: 12),
const Text(
'风急天高猿啸哀,\n渚清沙白鸟飞回。\n无边落木萧萧下,\n不尽长江滚滚来。'
'\n万里悲秋常作客,\n百年多病独登台。\n艰难苦恨繁霜鬓,\n潦倒新停浊酒杯。\n',
textAlign: TextAlign.center,
style: TextStyle(color: Colors.black, fontSize: 15),
),
],
),
),
);
}
// 详情页的Image size是250
Widget _buildImageWidget(int index) {
return const FlutterLogo(size: 250);
}
}
效果图
4 使用Hero实现的转场动画
实现Widget切换页面时飞到下一页的动画,使用Hero Widget包裹列表与详情页的图片Widget,并设置相同的tag即可。
修改 _buildImageWidget,使用Hero包裹FlutterLogo,并传入唯一的tag
。
列表页
// 列表页的Image size是120
Widget _buildImageWidget(int index) {
// 同一页面的hero不能有多个相同tag
return Hero(
tag: 'hero_tag_$index',
child: const FlutterLogo(size: 120),
);
}
详情页
// 详情页的Image size是250
Widget _buildImageWidget(int index) {
return Hero(
tag: 'hero_tag_$index',
child: const FlutterLogo(size: 250),
);
}
动画效果