简体   繁体   English

使用 AnimationController 使其第二次可见后无法为颤动小部件设置动画

[英]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:到目前为止我已经尝试过:

  • Create the _controller outside/inside widget build.在小部件构建的外部/内部创建_controller
  • Check if the widget is mounted before calling it在调用之前检查小部件是否已安装
  • Change the AnimationController state to false anytime the widget is hidden.每当隐藏小部件时,将AnimationController状态更改为 false。

None has worked.没有一个奏效。 Any idea what is wrong in my code:知道我的代码有什么问题:
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
                                ),
                              ]),
                        ),                 
                    ),
                  ),
          );
    }
  }
}

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在应用实际解决方案之前,您需要清除的几件事是

  1. Neven use var keyword to initialize a disposable type甚至不使用 var 关键字来初始化一次性类型
  2. Don't reinitialize your variable after declaration like how you have done it in initState and StartListening不要像在 initState 和 StartListening 中那样在声明后重新初始化变量

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.

相关问题 如何使用 AnimationController 为文本小部件设置动画 - How to animate a text widget with an AnimationController 在 AnimationController.dispose() 之后调用 AnimationController.stop() - 在 Flutter 上使用 ScaleTap + TabBar 时 - AnimationController.stop() called after AnimationController.dispose() - when using ScaleTap + TabBar on Flutter 当控件在抖动中变得可见时,如何对其进行动画处理? - How to animate a widget when it becomes visible in flutter? Flutter 错误:AnimationController.stop() 在 AnimationController.dispose() 之后调用 - Flutter error: AnimationController.stop() called after AnimationController.dispose() 单击按钮后使文本小部件可见 - Making a Text Widget visible after button click 如何使用 Flutter AnimationController 和 Transform 旋转图像? - How to rotate an image using Flutter AnimationController and Transform? Flutter 如何从另一个小部件访问 AnimationController 方法 - Flutter how to access AnimationController methods from another widget Flutter:AnimationController.stop() 在 AnimationController.dispose() 之后调用 AnimationController 方法不应在调用 dispose 之后使用。) - Flutter : AnimationController.stop() called after AnimationController.dispose() AnimationController methods should not be used after calling dispose.) Flutter 延迟 Animation 代码错误:AnimationController.forward() 在 AnimationController.dispose() 之后调用 - Flutter Delayed Animation code Error : AnimationController.forward() called after AnimationController.dispose() Flutter 中小部件的动画位置 - Animate position of a widget in Flutter
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM