【问题标题】:Can't animate flutter widget after making it visible for a second time using AnimationController使用 AnimationController 使其第二次可见后无法为颤振小部件设置动画
【发布时间】:2020-11-08 05:21:36
【问题描述】:

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

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

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

  • 创建 _controller 外部/内部小部件构建。
  • 在调用之前检查小部件是否已挂载
  • 在小部件隐藏时将 AnimationController 状态更改为 false。

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

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

【问题讨论】:

    标签: flutter animationcontroller


    【解决方案1】:

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

    _controller.isAnimating
        ? _controller.stop()
        : _controller.forward();
    

    【讨论】:

      【解决方案2】:

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

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

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

      if(_animationController){
        _animationController.dispose()
      }
      

      其次,尝试使用

      if(mounted){
        // your code
      }
      

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

      【讨论】:

        【解决方案3】:

        当动画完成时,_controller 上会调用dispose()

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

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

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2020-09-28
          • 2023-03-06
          • 2023-01-03
          • 2021-11-29
          • 1970-01-01
          • 2020-09-24
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多