flutter - Hero Animation 完成后启动 Widget Animation
问题描述
假设我有两个页面,Page1 和 Page2 包含一个 Hero。在 Page2 中,我想在 Hero 动画完成后启动一个 Widget 动画。
是否可以通过回调在 Page2 中获得有关英雄动画状态的通知?
到目前为止,我发现的唯一解决方法是向 Widget 动画添加延迟,以避免它在 Hero 动画完成之前开始:
class Page1 extends StatelessWidget {
@override
Widget build(BuildContext context) => Container(
child: Hero(
tag: "hero-tag",
child: IconButton(
icon: Icon(Icons.person),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (BuildContext context) => Page2(),
));
}),
),
);
}
class Page2 extends StatefulWidget {
@override
_Page2State createState() => _Page2State();
}
class _Page2State extends State<Page2> with TickerProviderStateMixin {
AnimationController _controller;
Animation _fabAnimation;
@override
void initState() {
super.initState();
_controller = AnimationController(
duration: const Duration(milliseconds: 400), vsync: this);
_fabAnimation = Tween<double>(
begin: 0.0,
end: 1.0,
).animate(
CurvedAnimation(
parent: _controller,
// delay to wait for hero animation to end
curve: Interval(
0.300,
1.000,
curve: Curves.ease,
),
),
);
_controller.forward();
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Container(
child: Row(
children: <Widget>[
Hero(
tag: "hero-tag",
child: Icon(Icons.person),
),
ScaleTransition(
scale: _fabAnimation,
child: FloatingActionButton(
child: Icon(
Icons.camera_alt,
),
onPressed: () {},
),
),
],
),
);
}
}
解决方案
好的,这是更好的答案。基于此处先前的答案。 Flutter:小部件构建上的运行方法完成
简短回答 我使用 WidgetsBinding 的 postFrameCallback() 测试了您的场景,如下所示,现在我认为相机图标上的补间动画在英雄动画完成后工作。您可以尝试将 _contoller.forward 包装在此回调中,如下所示。
//this ensures the animation is forwarded only after the widget is rendered
//atleast one frame.
// based on this answer:
//https://stackoverflow.com/questions/49466556/flutter-run-method-on-widget-build-complete
WidgetsBinding.instance.addPostFrameCallback((_) {
//Following future can be uncommented to check
//if the call back works after 5 seconds.
//Future.delayed(const Duration(seconds: 5), () => {
_controller.forward();
//});
});
我还尝试了下面给出的 RouteAwareWidget 选项,但没有太大区别。https://api.flutter.dev/flutter/widgets/RouteObserver-class.html
完整的工作代码
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.blue,
),
//navigatorObservers: [routeObserver],
initialRoute: '/',
routes: {
'/': (context) => Page1(),
'/page2': (context) => Page2(),
},
);
}
}
class Page1 extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Page 1'),
),
body: Center(
child: Hero(
tag: "hero-tag",
child: IconButton(
icon: Icon(Icons.person),
onPressed: () {
Navigator.pushNamed(context, '/page2');
}),
),
),
);
}
}
class Page2 extends StatefulWidget {
@override
_Page2State createState() => _Page2State();
}
class _Page2State extends State<Page2> with TickerProviderStateMixin {
AnimationController _controller;
Animation _fabAnimation;
@override
void initState() {
super.initState();
_controller = AnimationController(
duration: const Duration(milliseconds: 400), vsync: this);
_fabAnimation = Tween<double>(
begin: 0.0,
end: 1.0,
).animate(
CurvedAnimation(
parent: _controller,
// delay to wait for hero animation to end
// curve: Interval(
// 0.900,
// 1.000,
curve: Curves.ease,
//),
),
);
// this ensures the animation is forwarded only after the widget is rendered
//atleast one frame.
// based on:
//https://stackoverflow.com/questions/49466556/flutter-run-method-on-widget-build-complete
WidgetsBinding.instance.addPostFrameCallback((_) {
//Future.delayed(const Duration(seconds: 5), () =>
_controller.forward();
//);
});
//end
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Screen 2')),
body: Center(
child: Row(
children: <Widget>[
Hero(
tag: "hero-tag",
child: Icon(Icons.person),
),
ScaleTransition(
scale: _fabAnimation,
child: FloatingActionButton(
child: Icon(
Icons.camera_alt,
),
onPressed: () {
Navigator.pop(
context,
); // Added to avoid exceptions of no material widget.
},
),
),
],
),
),
);
}
}
推荐阅读
- python - 在 Python 中更改蜘蛛网图的 r 值
- machine-learning - 为什么机器学习算法不处理分类数据而需要将分类数据编码为数值数据?
- python - Python Transformer 异常模式的用处?
- html - 使用 Go 提供 HTML 页面
- c# - 在 WPF DataGrid 中使用多个 XML 文档
- python - 如何在 python 3.8 中从 tkinter 中的文本获取输入
- javascript - 通过 ajax 发送到 php 的数据是否可操作?
- arduino - AT+CIPSEND GET 请求返回 400 ESP8266
- java - 如何创建自动离线实时更新文本的文本视图
- ios - 如何在swift中将标题视图背景颜色与表格视图分开