0

我正在使用 AnimationController 为小部件制作动画(小部件是所附图像中显示的红色波浪)。在用户点击红色按钮说话后,小部件开始visibility = false并在 10 秒内变为真。我面临的问题是第二次点击红色按钮时出现错误:

AnimationController.stop() 在 AnimationController.dispose() 之后调用。

并且该小部件再也不会显示。由于我没有处理只是隐藏它的小部件,我无法理解发生了什么。到目前为止我已经尝试过:

  • 创建_controller外部/内部小部件构建。
  • 在调用它之前检查小部件是否已安装
  • 只要小部件被隐藏,就将状态更改AnimationController为 false。

没有一个有效。知道我的代码有什么问题:
spinkitWaveWidget

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
                                ),
                              ]),
                        ),                 
                    ),
                  ),
          );
    }
  }
}
4

3 回答 3

0

在此处应用实际解决方案之前,您需要清除的几件事是

  1. 甚至不使用 var 关键字来初始化一次性类型
  2. 不要在声明后重新初始化变量,就像在 initState 和 StartListening 中所做的那样

要解决您的问题,您可以将 dispose 方法包装为

if(_animationController){
  _animationController.dispose()
}

其次,尝试使用

if(mounted){
  // your code
}

在您创建的回调上,这将防止您面临的错误

于 2020-11-13T06:59:17.597 回答
0

我认为问题是,您声明了_controller2 次。第一次在initState(){}它开始播放的地方,第二次在startListening(){}它被覆盖并且不再播放的地方。如果你想开始/停止动画,你可以这样做:

_controller.isAnimating
    ? _controller.stop()
    : _controller.forward();
于 2020-11-12T23:12:30.230 回答
0

dispose()_controller动画完成时被调用。

正如其他评论者所指出的,您的代码需要解决一些问题,但我将专注于您的AnimationController问题的解决方案。

有几种方法可以防止此错误。_controller.repeat(reverse: true);最简单的方法是在初始化控制器后调用initState. 这将导致它无限期地来回运行。然后您可以简单地切换_isListening以显示/隐藏动画。

您还可以initState在每次调用startListening(). 如果这样做,您需要确保在初始化新控制器之前处理掉控制器。这可以通过调用来完成_controller.stop()。根据您的需要,这可以是设置Durationvia之后的回调Future.delayed(),释放按钮时,或任何数量的其他方法。

于 2020-11-18T04:48:06.370 回答