Flutter 中多个补间动画的问题 - 包含视频
Posted
技术标签:
【中文标题】Flutter 中多个补间动画的问题 - 包含视频【英文标题】:Problems with multiple tween animations in Flutter - Videos Included 【发布时间】:2019-04-21 05:37:21 【问题描述】:我正在尝试创建的某个动画有一个奇怪的颤振问题。
我正在尝试将图像动画到屏幕上。 我希望它在 x 轴上移动,我也希望它慢慢淡入。
所以我想到了 - Positioned
和 Opacity
,并使用补间动画来设置它们的值。
Positioned
和 Opacity
小部件单独工作时效果很好,但是当我将两者结合时 - 我得到一个奇怪的动画,它只是在一段时间后(大约 3 秒)才开始绘制。
我尝试打印animation.value
,它似乎很好,从0.0
慢慢爬升到1.0
- 但云突然出现在大约 3 秒后。
我尝试将它们分离到不同的控制器,我认为这可能是罪魁祸首,但不是。
TLDR 视频:
Opacity Animation Only
Positioned Animation Only
Both Animations Combined - NOT GOOD
这是小部件的代码:
import 'package:app/weather/widgets/CloudProperties.dart';
import 'package:flutter/widgets.dart';
class WeatherCloudWidget extends StatefulWidget
final double sunSize;
final CloudProperties properties;
WeatherCloudWidget(Key key, this.properties, this.sunSize)
: super(key: key);
@override
State<StatefulWidget> createState() => _WeatherCloudWidget();
class _WeatherCloudWidget extends State<WeatherCloudWidget>
with TickerProviderStateMixin
AnimationController controller;
AnimationController controller2;
Animation<double> position;
Animation<double> opacity;
@override
initState()
super.initState();
_startAnimation();
@override
Widget build(BuildContext context)
// screen width and height
final screenWidth = MediaQuery.of(context).size.width;
final screenHeight = MediaQuery.of(context).size.height;
final properties = widget.properties;
var vertical =
screenHeight * 0.5 + (widget.sunSize * properties.verticalOffset * -1);
var horizontal = (screenWidth * 0.5) + (widget.sunSize * position.value);
print(opacity.value);
// both Positioned & Opacity widgets
return Positioned(
left: horizontal,
top: vertical,
child: Opacity(
opacity: opacity.value,
child: Image.asset(
properties.path,
width: properties.getScaledWidth(widget.sunSize),
height: properties.getScaledHeight(widget.sunSize),
),
));
// Positioned only
return Positioned(
left: horizontal,
top: vertical,
child: Image.asset(
properties.path,
width: properties.getScaledWidth(widget.sunSize),
height: properties.getScaledHeight(widget.sunSize),
));
// Opacity only
return Positioned(
left: (screenWidth * 0.5) + (widget.sunSize * properties.tween[1]),
top: vertical,
child: Opacity(
opacity: opacity.value,
child: Image.asset(
properties.path,
width: properties.getScaledWidth(widget.sunSize),
height: properties.getScaledHeight(widget.sunSize),
),
));
@override
dispose()
controller.dispose();
controller2.dispose();
super.dispose();
void _startAnimation()
controller = AnimationController(
duration: const Duration(milliseconds: 5000), vsync: this);
controller2 = AnimationController(
duration: const Duration(milliseconds: 5000), vsync: this);
position = Tween(
begin: widget.properties.tween[0], end: widget.properties.tween[1])
.animate(
new CurvedAnimation(parent: controller, curve: Curves.decelerate))
..addListener(() => setState(() ));
opacity = Tween(begin: 0.0, end: 1.0).animate(controller2)
..addListener(() => setState(() ));
controller.forward();
controller2.forward();
【问题讨论】:
【参考方案1】:好的,伙计们。我设法使用SlideTransition
和FadeTransition
对此进行了排序。
我想我们应该只将Transition
小部件用于...过渡?而像Positioned
和Opacity
这样的东西是针对更多静态小部件的?不确定...
它的样子:https://youtu.be/hj7PkjXrgfg
无论如何,这里是替换代码,如果有人在寻找参考:
class WeatherCloudWidget extends StatefulWidget
final double sunSize;
final CloudProperties properties;
WeatherCloudWidget(Key key, this.properties, this.sunSize)
: super(key: key);
@override
State<StatefulWidget> createState() => _WeatherCloudWidget();
class _WeatherCloudWidget extends State<WeatherCloudWidget>
with TickerProviderStateMixin
AnimationController controller;
Animation<Offset> position;
Animation<double> opacity;
final alphaTween = new Tween(begin: 0.0, end: 1.0);
@override
initState()
super.initState();
_startAnimation();
@override
Widget build(BuildContext context)
// screen width and height
final screenWidth = MediaQuery.of(context).size.width;
final screenHeight = MediaQuery.of(context).size.height;
final properties = widget.properties;
var vertical = (screenHeight * 0.5) +
(widget.sunSize * properties.verticalOffset * -1);
var horizontal =
(screenWidth * 0.5) + (widget.sunSize * properties.tweenEnd);
return Positioned(
left: horizontal,
top: vertical,
child: SlideTransition(
position: position,
child: FadeTransition(
opacity: opacity,
child: Image.asset(
properties.path,
width: properties.getScaledWidth(widget.sunSize),
height: properties.getScaledHeight(widget.sunSize),
),
)),
);
@override
dispose()
controller.dispose();
super.dispose();
void _startAnimation()
controller = AnimationController(
duration: const Duration(milliseconds: 2000), vsync: this);
position = new Tween<Offset>(
begin: new Offset(widget.properties.tweenStart, 0.0),
end: new Offset(0.0, 0.0),
).animate(new CurvedAnimation(parent: controller, curve: Curves.decelerate));
opacity = alphaTween.animate(controller);
controller.forward();
【讨论】:
监听器中不需要addListener
和setState
(它会重建WeatherCloudWidget
)-controller.forward();
就足够了
您介意制作新版本的视频吗? (我很好奇):)
嘿@Feu,我已将视频添加到答案中。
@pskink - 你当然是对的!这是我在动画不起作用时尝试过的,忘记删除它。
理论上你的WeatherCloudWidget
现在可能是StatelessWidget
?还是不行?以上是关于Flutter 中多个补间动画的问题 - 包含视频的主要内容,如果未能解决你的问题,请参考以下文章