[英]Can't animate flutter widget after making it visible for a second time using AnimationController
I'm animating a widget using AnimationController (The widget is the red wave shown in the image attached).我正在使用 AnimationController 为小部件设置动画(小部件是所附图像中显示的红色波浪)。 The widget starts with
visibility = false
and turns true for periods of 10 seconds after the user hits the red button to speak.该小部件以
visibility = false
开始,并在用户点击红色按钮发言后的10 秒内变为真。 The problem I'm facing is that when hitting the red button for a second time I get the error:我面临的问题是,第二次点击红色按钮时出现错误:
AnimationController.stop() called after AnimationController.dispose().
AnimationController.stop() 在 AnimationController.dispose() 之后调用。
And the widget never shows again.并且该小部件再也不会显示。 Since I'm not disposing the widget just hiding it, I can't understand what is going on.
由于我没有处理小部件只是隐藏它,我无法理解发生了什么。 I have tried so far:
到目前为止我已经尝试过:
_controller
outside/inside widget build._controller
。AnimationController
state to false anytime the widget is hidden.AnimationController
状态更改为 false。 None has worked.没有一个奏效。 Any idea what is wrong in my code:
知道我的代码有什么问题:
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> with TickerProviderStateMixin {
var _controller;
var spinkitWave;
stt.SpeechToText speech = stt.SpeechToText();
@override
void initState() {
super.initState();
_controller = AnimationController(vsync:this, duration: Duration(seconds:1), lowerBound:0, upperBound:0.1)
..addStatusListener((status) {
if (status == AnimationStatus.completed) {
if (mounted) {
_controller.reverse();
}
}});
@override
dispose() {
_controller.dispose(); // you need this
super.dispose();
}
void startListening() {
_controller = AnimationController(vsync:this, duration: Duration(seconds:1), lowerBound:0, upperBound:0.1);
speech.listen(onResult: resultListener,
onSoundLevelChange: soundLevelListener,
cancelOnError: true,);
setState(() {});
}
@override
Widget build(BuildContext context) {
spinkitWave = SpinKitWave(
color: Colors.redAccent,
type: SpinKitWaveType.center,
controller: _controller,
);
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.red,
),
home: Builder(
builder: (context) => Scaffold(
appBar: AppBar(
title: Text("Leurebeng"),
),
body: Center(
Positioned(
bottom: 10,
child: Stack(
alignment: AlignmentDirectional.bottomCenter,
children: <Widget>[
SizedBox
width: 110.0,
height: 110.0,
child: Visibility(
visible: !speech.isListening,
child: FloatingActionButton(
onPressed:
_available ? startListening : initSpeechState,
tooltip: 'Increment',
child: Icon(Icons.mic),
),
),
),
Visibility(
visible: speech.isListening, //Turns true or false after red button pressed
child:
spinkitWave
),
]),
),
),
),
);
}
}
}
I think the problem is, that you declare _controller
2 times.我认为问题是,您声明了
_controller
2 次。 First time in initState(){}
where it starts playing and second time in startListening(){}
where it is overridden and never played again.第一次在
initState(){}
中开始播放,第二次在startListening(){}
中被覆盖并且不再播放。 If you want to start/stop the animation, you can do it like this :如果你想开始/停止动画,你可以这样做:
_controller.isAnimating
? _controller.stop()
: _controller.forward();
Few things you need to clear it before applying actual solution here are在应用实际解决方案之前,您需要清除的几件事是
To solve your problem you can wrap your dispose method as为了解决您的问题,您可以将您的处置方法包装为
if(_animationController){
_animationController.dispose()
}
And second, try using其次,尝试使用
if(mounted){
// your code
}
on the callback you have created which will prevent for the error you are facing在您创建的回调上,这将防止您面临的错误
dispose()
is being called on the _controller
when the animation completes.当动画完成时,将在
_controller
上调用dispose()
。
As noted by other commenters, there are a few things that need to be addressed with your code, but I will focus on the solutions to your AnimationController
problems.正如其他评论者所指出的,您的代码需要解决一些问题,但我将重点关注您的
AnimationController
问题的解决方案。
There are a few ways that you could prevent this error.有几种方法可以防止此错误。 The simplest is to call
_controller.repeat(reverse: true);
最简单的就是调用
_controller.repeat(reverse: true);
after initializing your controller in initState
.在
initState
初始化控制器initState
。 This will cause it to run back and forth indefinitely.这将导致它无限期地来回运行。 Then you can simply toggle
_isListening
to show/hide the animation.然后你可以简单地切换
_isListening
来显示/隐藏动画。
You could also remove the initialization in initState
and re-initialize upon every call to startListening()
.您还可以删除
initState
的初始化并在每次调用startListening()
时重新初始化。 If you do this, you will need to be sure to dispose of the controller before initializing a new one.如果您这样做,您需要确保在初始化新控制器之前处理控制器。 This can be done by calling
_controller.stop()
.这可以通过调用
_controller.stop()
来完成。 According to your needs, this can be a callback after a set Duration
via Future.delayed()
, upon release of a button, or any number of other methods.根据您的需要,这可以是通过
Future.delayed()
设置的Duration
之后的回调,释放按钮或任意数量的其他方法。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.