Flutter Hero动画
- Hero指的是可以在路由(页面)之间“飞行”的widget。
- 使用Flutter的Hero widget创建hero动画。
- 将 hero从一个路由飞到另一个路由。
- 将 hero 的形状从圆形转换为矩形,同时将其从一个路由飞到另一个路由的过程中进行动画处理。
- Flutter中的Hero widget实现了通常称为 共享元素转换 或 共享元素动画的动画风格。
你可能多次看过 hero 动画。例如,路由显示代表待售物品的缩略图列表。选择一个条目会将其跳转到一个新路由,新页面中包含更多详细信息和“购买”按钮。 在Flutter中将图片从一个路由飞到另一个路由称为hero动画,尽管相同的动作有时也称为 共享元素转换。
Hero动画的基本结构
- 在不同路由中使用两个 hero widget,但使用匹配的标签来实现动画。
- 导航器管理包含应用程序路由的栈。
- 从导航器栈中推入或弹出路由会触发动画。
- Flutter框架会计算一个补间矩形 ,用于定义在从源路由“飞行”到目标路由时 hero 的边界。在“飞行”过程中, hero 会移动到应用程序上的一个叠加层,以便它出现在两个页面之上。
示例
假设有两个路由A和B,他们的内容交互如下:
A:包含一个用户头像,圆形,点击后跳到B路由,可以查看大图。
B:显示用户头像原图,矩形。
在AB两个路由之间跳转的时候,用户头像会逐渐过渡到目标路由页的头像上,接下来我们先看看代码:
import 'package:flutter/material.dart';
class HeroAnimationRoute extends StatelessWidget {
const HeroAnimationRoute({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
padding: EdgeInsets.only(top: 100),
alignment: Alignment.topCenter,
child: Column(
children: <Widget>[
InkWell(
child: Hero(
tag: "avatar", //唯一标记,前后两个路由页Hero的tag必须相同
child: ClipOval(
child: Image.network('https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.jj20.com%2Fup%2Fallimg%2F511%2F101611154647%2F111016154647-10-1200.jpg&refer=http%3A%2F%2Fimg.jj20.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1644588215&t=9a40338757751be9d2684f0d3c80ae31',
width: 100.0,
),
),
),
onTap: () {
//打开B路由
Navigator.push(context, PageRouteBuilder(
pageBuilder: (
BuildContext context,
animation,
secondaryAnimation,
) {
return FadeTransition(
opacity: animation,
child: Scaffold(
appBar: AppBar(
title: Text("原图"),
),
body: HeroAnimationRouteB(),
),
);
},
));
},
),
Padding(
padding: const EdgeInsets.only(top: 8.0),
child: Text("点击头像"),
)
],
),
),
);
}
}
class HeroAnimationRouteB extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Center(
child: Hero(
tag: "avatar", //唯一标记,前后两个路由页Hero的tag必须相同
child: Image.network('https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.jj20.com%2Fup%2Fallimg%2F511%2F101611154647%2F111016154647-10-1200.jpg&refer=http%3A%2F%2Fimg.jj20.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1644588215&t=9a40338757751be9d2684f0d3c80ae31'),
),
);
}
}
效果渐变:
我们可以看到,实现 Hero 动画只需要用Hero
组件将要共享的 widget 包装起来,并提供一个相同的 tag 即可,中间的过渡帧都是 Flutter 框架自动完成的。必须要注意, 前后路由页的共享Hero
的 tag 必须是相同的,Flutter 框架内部正是通过 tag 来确定新旧路由页widget的对应关系的。
Hero 动画的原理比较简单,Flutter 框架知道新旧路由页中共享元素的位置和大小,所以根据这两个端点,在动画执行过程中求出过渡时的插值(中间态)即可,而感到幸运的是,这些事情不需要我们自己动手,Flutter 已经帮我们做了,有兴趣可以去看 Hero 动画相关的源码。