如何"undispose" 动画控制器进行复用?

How to "undispose" animation controller for reuse?

我是 Flutter 的新手,在使用生命周期方法和动画控制器时遇到了一些麻烦。

当我按下底部按钮时它开始播放动画,当我按下中间的圆圈时它停止动画,如果我再次按下底部按钮我得到错误:

AnimationController.stop() 在 AnimationController.dispose() 之后调用 调用 dispose 后不应使用 AnimationController 方法。 'package:flutter/src/animation/animation_controller.dart': 断言失败:第 767 行 pos 7:'_ticker != null'

我希望动画重新开始播放。感谢您的任何建议!

import 'package:flutter/cupertino.dart';
import 'package:provider/provider.dart';
import 'package:flutter/material.dart';
import 'model/app_state_model.dart';
import 'dart:developer' as developer;
import 'package:flutter_spinkit/flutter_spinkit.dart';

class ProductListTab extends StatefulWidget {
  @override
  _ProductListTabState createState() => _ProductListTabState();
}

class _ProductListTabState extends State<ProductListTab>
    with SingleTickerProviderStateMixin {
  var _isActive = true;
  var _time = " ";
  var _resultBox;

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      crossAxisAlignment: CrossAxisAlignment.stretch,
      children: [
        Expanded(
            flex: 3,
            child: Container(
              color: Colors.lightBlue,
              child: Padding(
                  padding: const EdgeInsets.all(30.0),
                  child: Align(
                    alignment: Alignment(0, .6),
                    child: Container(
                        width: 150,
                        height: 150,
                        child: OutlinedButton(
                            //elevation: 0.0,
                            style: OutlinedButton.styleFrom(
                                shape: CircleBorder(),
                                backgroundColor: Colors.blue),
                            onPressed: () {
                              setState(() {
                                _time = "999";
                              });
                            },
                            child: AnimatedSwitcher(
                              duration: Duration(seconds: 1),
                              child: ResultBox(time: _time),
                            ))),
                  )),
            )),
        Expanded(
          flex: 2,
          child: Padding(
            padding: const EdgeInsets.all(30),
            child: Row(
              mainAxisAlignment: MainAxisAlignment.center,
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                CupertinoButton(
                  child: Text(_isActive ? 'Cancel' : 'Ready'),
                  onPressed: () {
                    setState(() {
                      _isActive = !_isActive;
                      _time = null;
                    });
                  },
                  color: Colors.amber,
                )
              ],
            ),
          ),
        )
      ],
    );
  }
}

class ResultBox extends StatefulWidget {
  final String time;
  const ResultBox({
    String this.time,
    Key key,
  }) : super(key: key);

  @override
  _ResultBoxState createState() => _ResultBoxState();
}

class _ResultBoxState extends State<ResultBox>
    with SingleTickerProviderStateMixin {
  AnimationController _controller;
  void initState() {
    this._controller =
        AnimationController(vsync: this, duration: Duration(seconds: 1));
    super.initState();
    _controller.reset();
  }

  Widget build(BuildContext context) {
    var _resultRow;
    if (widget.time != null) {
      _resultRow = Row(mainAxisAlignment: MainAxisAlignment.center, children: [
        Text(
          widget.time,
          style: TextStyle(color: Colors.white, fontSize: 50),
        ),
        Text(
          "ms",
          style: TextStyle(color: Colors.white, fontSize: 20),
        ),
      ]);
    } else {
      _resultRow = SpinKitWave(color: Colors.white, controller: _controller);
    }

    return FittedBox(
      fit: BoxFit.fitWidth,
      child: _resultRow,
    );
  }

  Widget dispose() {
    this._controller.dispose();
  }
}

如果您查看您在评论中发送的 SpinkitWave class: https://github.com/jogboms/flutter_spinkit/blob/master/lib/src/wave.dart

你会看到下面是它的initState方法:

  @override
  void initState() {
    super.initState();

    _controller = (widget.controller ?? AnimationController(vsync: this, duration: widget.duration))..repeat();
  }

这是在说,如果用户传入了一个 AnimationController 作为参数,则使用该 AnimationController,如果没有则创建一个新的 AnimationController 并使用用户传入的持续时间。因此,如果您需要 AnimationController 是为了控制 SpinKitWave 小部件,那么我建议您最好将持续时间传递给它,然后让它在内部管理 AnimationController。即使用以下创建小部件。

// As you no longer need to handle the state of the AnimationController you can 
// convert the ResultBox into a StatelessWidget
class ResultBox extends StatelessWidget {
  final String time;
  const ResultBox({
   this.time,
    Key key,
  }) : super(key: key);

  Widget build(BuildContext context) {
    var _resultRow;
    if (widget.time != null) {
      _resultRow = Row(mainAxisAlignment: MainAxisAlignment.center, children: [
        Text(
          widget.time,
          style: TextStyle(color: Colors.white, fontSize: 50),
        ),
        Text(
          "ms",
          style: TextStyle(color: Colors.white, fontSize: 20),
        ),
      ]);
    } else {
      // The controller argument has been removed here and the duration
      // argument added
      _resultRow = SpinKitWave(color: Colors.white, duration: const Duration(seconds: 1);
    }

    return FittedBox(
      fit: BoxFit.fitWidth,
      child: _resultRow,
    );
  }
}