0
votes

Impossible d'animer le widget Flutter après l'avoir rendu visible une deuxième fois à l'aide d'AnimationController

J'anime un widget en utilisant AnimationController (Le widget est la vague rouge montrée dans l'image ci-jointe). Le widget commence par visibility = false et devient vrai pendant des périodes de 10 secondes après que l'utilisateur a appuyé sur le bouton rouge pour parler. Le problème auquel je suis confronté est que lorsque j'appuie sur le bouton rouge une deuxième fois, j'obtiens l'erreur:

AnimationController.stop () appelé après AnimationController.dispose ().

Et le widget ne s'affiche plus jamais. Puisque je ne suis pas en train de supprimer le widget, je ne peux pas comprendre ce qui se passe. J'ai essayé jusqu'à présent:

  • Créez le widget _controller extérieur / intérieur.
  • Vérifiez si le widget est monté avant de l'appeler
  • Modifiez l'état AnimationController sur false à chaque fois que le widget est masqué.

Aucun n'a fonctionné. Toute idée de ce qui ne va pas dans mon 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
                                ),
                              ]),
                        ),                 
                    ),
                  ),
          );
    }
  }
}


0 commentaires

3 Réponses :


0
votes

Je pense que le problème est que vous déclarez _controller 2 fois. Première fois dans initState(){} où il commence à jouer et deuxième fois dans startListening(){} où il est écrasé et jamais lu à nouveau. Si vous souhaitez démarrer / arrêter l'animation, vous pouvez le faire comme ceci:

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


0 commentaires

0
votes

Peu de choses dont vous avez besoin pour le nettoyer avant d'appliquer la solution réelle sont ici

  1. Neven utilisez le mot clé var pour initialiser un type jetable
  2. Ne réinitialisez pas votre variable après la déclaration comme vous l'avez fait dans initState et StartListening

Pour résoudre votre problème, vous pouvez emballer votre méthode d'élimination comme

if(mounted){
  // your code
}

Et deuxièmement, essayez d'utiliser

if(_animationController){
  _animationController.dispose()
}

sur le rappel que vous avez créé qui empêchera l'erreur que vous rencontrez


0 commentaires

0
votes

dispose() est appelé sur le _controller fois l'animation terminée.

Comme indiqué par d'autres commentateurs, il y a quelques points à résoudre avec votre code, mais je me concentrerai sur les solutions à vos problèmes d' AnimationController .

Vous pouvez éviter cette erreur de plusieurs manières. Le plus simple est d'appeler _controller.repeat(reverse: true); après avoir initialisé votre contrôleur dans initState . Cela le fera aller et venir indéfiniment. Ensuite, vous pouvez simplement basculer _isListening pour afficher / masquer l'animation.

Vous pouvez également supprimer l'initialisation dans initState et la réinitialiser à chaque appel à startListening() . Si vous faites cela, vous devrez vous assurer de disposer du contrôleur avant d'en initialiser un nouveau. Cela peut être fait en appelant _controller.stop() . Selon vos besoins, cela peut être un rappel après une Duration définie via Future.delayed() , lors du relâchement d'un bouton, ou de toute autre méthode.


0 commentaires