文章目录
◯、Hero 动画简介
一、创建 Hero 动画核心组件
二、创建源页面
三、创建目的页面
四、页面跳转
五、完整代码示例
六、相关资源
◯、Hero 动画简介
Hero Widget 动画效果 : Hero 通过动画从 源界面 运动到 目标界面 时 , 目标界面 透明度逐渐增加 , 淡入显示 ;
Hero 是界面的组成部分 , 在 源界面 和 目标界面 都存在该组件 ;
Hero 动画涉及到的 API 较多 ;
一、创建 Hero 动画核心组件
Hero 动画 tag 标识 : Hero 动画作用的组件在两个界面中都存在 , 给这两个 Hero 组件都设置相同的标识 , 通过该标识可以标识两个 Hero 组件之间进行动画过渡 ;
该 Hero 动画组件封装内容 :
VoidCallback onTap : 从外部传入一个回调事件 , 这是点击组件后 , 回调的函数 ;
String imageUrl : 作为 Hero 动画的 tag 标识 , 同时也是图片的 url 网络地址 ;
double width : 用于约束 Hero 组件的宽度 ;
代码示例 : 这里定义核心组件 Hero 组件 , 传入 tag 标识 , 与 Hero 动画作用的组件 ;
/// Hero 组件 , 跳转前后两个页面都有该组件 class HeroWidget extends StatelessWidget{ /// 构造方法 const HeroWidget({Key key, this.imageUrl, this.width, this.onTap}) : super(key: key); /// Hero 动画之间关联的 ID , 通过该标识 /// 标识两个 Hero 组件之间进行动画过渡 /// 同时该字符串也是图片的 url 网络地址 final String imageUrl; /// 点击后的回调事件 final VoidCallback onTap; /// 宽度 final double width; @override Widget build(BuildContext context) { return SizedBox( width: width, /// 这里定义核心组件 Hero 组件 , 传入 tag 标识 , 与 Hero 动画作用的组件 child: Hero(tag: imageUrl, child: Material( color: Colors.transparent, /// 按钮 child: InkWell( /// 按钮点击事件 onTap: onTap, child: Image.network(imageUrl, fit: BoxFit.contain,), ), ),), ); } }
二、创建源页面
创建一个 StatelessWidget 组件作为源页面 , 其中封装 HeroWidget 组件 , 作为显示的核心组件 , 传入一个 VoidCallback 方法 , 在该方法中跳转到目的界面 ;
class HeroAnimation extends StatelessWidget{ @override Widget build(BuildContext context) { // 时间膨胀系数 , 用于降低动画运行速度 timeDilation = 10.0; return MaterialApp( home: Scaffold( appBar: AppBar( title: Text("Hero 动画演示( 跳转前页面 )"), ), body: Container( color: Colors.white, padding: EdgeInsets.all(20), alignment: Alignment.bottomRight, child: HeroWidget( imageUrl: "https://ucc.alicdn.com/images/user-upload-01/20210329101628636.jpg", width: 300, // 点击事件 , 这里点击该组件后 , 跳转到新页面 onTap: (){ }, ), ), ), ); } }
三、创建目的页面
创建目的界面 : 这里直接在代码中创建 , 该界面中也封装了 HeroWidget 组件 , 其 tag 与源界面 HeroWidget 组件相同 , 这样就可以保证这两个界面互相跳转时 , 能触发 Hero 动画 ;
MaterialPageRoute( builder: (context){ /// 跳转到的新界面再此处定义 return MaterialApp( home: Scaffold( appBar: AppBar( title: Text("Hero 动画演示( 跳转后页面 )"), ), body: Container( color: Colors.white, padding: EdgeInsets.all(20), alignment: Alignment.topLeft, child: HeroWidget( imageUrl: "https://ucc.alicdn.com/images/user-upload-01/20210329101628636.jpg", width: 100, onTap: (){ /// 退出当前界面 Navigator.of(context).pop(); }, ), ), ), ); } )
四、页面跳转
使用 Navigator 进行页面跳转 , 这个页面直接在方法中创建出来 ;
Navigator.of(context).push( MaterialPageRoute( builder: (context){ /// 跳转到的新界面再此处定义 return MaterialApp( home: Scaffold( ), ); } ) );
如果出现页面跳转错误 , 参考 【错误记录】Flutter 界面跳转报错 ( Navigator operation requested with a context that does not include a Naviga ) 解决 ;
五、完整代码示例
完整代码示例 :
import 'package:flutter/material.dart'; import 'package:flutter/scheduler.dart' show timeDilation; void main() { runApp( MaterialApp( home: HeroAnimation(), ) ); } /// Hero 组件 , 跳转前后两个页面都有该组件 class HeroWidget extends StatelessWidget{ /// 构造方法 const HeroWidget({Key key, this.imageUrl, this.width, this.onTap}) : super(key: key); /// Hero 动画之间关联的 ID , 通过该标识 /// 标识两个 Hero 组件之间进行动画过渡 /// 同时该字符串也是图片的 url 网络地址 final String imageUrl; /// 点击后的回调事件 final VoidCallback onTap; /// 宽度 final double width; @override Widget build(BuildContext context) { return SizedBox( width: width, /// 这里定义核心组件 Hero 组件 , 传入 tag 标识 , 与 Hero 动画作用的组件 child: Hero(tag: imageUrl, child: Material( color: Colors.transparent, /// 按钮 child: InkWell( /// 按钮点击事件 onTap: onTap, child: Image.network(imageUrl, fit: BoxFit.contain,), ), ),), ); } } class HeroAnimation extends StatelessWidget{ @override Widget build(BuildContext context) { // 时间膨胀系数 , 用于降低动画运行速度 timeDilation = 10.0; return MaterialApp( home: Scaffold( appBar: AppBar( title: Text("Hero 动画演示( 跳转前页面 )"), ), body: Container( color: Colors.white, padding: EdgeInsets.all(20), alignment: Alignment.bottomRight, child: HeroWidget( imageUrl: "https://ucc.alicdn.com/images/user-upload-01/20210329101628636.jpg", width: 300, // 点击事件 , 这里点击该组件后 , 跳转到新页面 onTap: (){ print("点击事件触发, 切换到新界面"); Navigator.of(context).push( MaterialPageRoute( builder: (context){ /// 跳转到的新界面再此处定义 return MaterialApp( home: Scaffold( appBar: AppBar( title: Text("Hero 动画演示( 跳转后页面 )"), ), body: Container( color: Colors.white, padding: EdgeInsets.all(20), alignment: Alignment.topLeft, child: HeroWidget( imageUrl: "https://ucc.alicdn.com/images/user-upload-01/20210329101628636.jpg", width: 100, onTap: (){ /// 退出当前界面 Navigator.of(context).pop(); }, ), ), ), ); } ) ); }, ), ), ), ); } }
运行效果 :
六、相关资源
参考资料 :
Flutter 官网 : https://flutter.dev/
Flutter 插件下载地址 : https://pub.dev/packages
Flutter 开发文档 : https://flutter.cn/docs ( 强烈推荐 )
官方 GitHub 地址 : https://github.com/flutter
Flutter 中文社区 : https://flutter.cn/
Flutter 实用教程 : https://flutter.cn/docs/cookbook
Flutter CodeLab : https://codelabs.flutter-io.cn/
Dart 中文文档 : https://dart.cn/
Dart 开发者官网 : https://api.dart.dev/
Flutter 中文网 : https://flutterchina.club/ , http://flutter.axuer.com/docs/
Flutter 相关问题 : https://flutterchina.club/faq/ ( 入门阶段推荐看一遍 )
GitHub 上的 Flutter 开源示例 : https://download.csdn.net/download/han1202012/15989510
Flutter 实战电子书 : https://book.flutterchina.club/chapter1/
重要的专题 :
Flutter 动画参考文档 : https://flutterchina.club/animations/
博客源码下载 :
GitHub 地址 : https://github.com/han1202012/flutter_animation ( 随博客进度一直更新 , 有可能没有本博客的源码 )
博客源码快照 : https://download.csdn.net/download/han1202012/16188742 ( 本篇博客的源码快照 , 可以找到本博客的源码 )