flutter - 在 flutter 中的 CircularProgressIndicator 上显示计时器进度

标签 flutter timer progress-bar

我正在使用 RestartableTimer(Timer 的子类)作为倒数计时器,在一定时间后将人们“踢出”表格。

我想显示那个计时器的进度,我喜欢循环进度慢慢填满的想法。

我没有展示我的代码,因为我真的没有什么可展示的。我在一个小部件中有一个完全静态的进度指示器和一个工作计时器(有状态或无状态,以效果最好的为准)。

我面临两个问题,这是我需要帮助的地方:

  • 我不知道如何每 x 毫秒检查一次计时器进度。我怎样才能做到这一点?我不需要复制粘贴代码,但我应该去了解更多“什么对象/哪个方向”?

  • 计时器进度未实现(NotImplementedException);有什么办法可以在其他地方找到等价物吗?除了那个部分,那个对象对我来说真的很好用。

我是 SOL 还是有办法做到这一点?

最佳答案

在 getter tick 中没有什么要实现的,因为 RestartableTimer 不是周期性的。您想要的是一个复杂得多的东西,RestartableTimer 无法帮助您。

首先,您需要一些东西来控制 CircularProgressIndicator 的进度:

class ProgressController {
  static const double smoothnessConstant = 250;

  final Duration duration;
  final Duration tickPeriod;

  Timer _timer;
  Timer _periodicTimer;

  Stream<void> get progressStream => _progressController.stream;
  StreamController<void> _progressController = StreamController<void>.broadcast();

  Stream<void> get timeoutStream => _timeoutController.stream;
  StreamController<void> _timeoutController = StreamController<void>.broadcast();

  double get progress => _progress;
  double _progress = 0;

  ProgressController({@required this.duration})
      : assert(duration != null),
        tickPeriod = _calculateTickPeriod(duration);

  void start() {
    _timer = Timer(duration, () {
      _cancelTimers();
      _setProgressAndNotify(1);
      _timeoutController.add(null);
    });

    _periodicTimer = Timer.periodic(
      tickPeriod,
      (Timer timer) {
        double progress = _calculateProgress(timer);
        _setProgressAndNotify(progress);
      },
    );
  }

  void restart() {
    _cancelTimers();
    start();
  }

  Future<void> dispose() async {
    await _cancelStreams();
    _cancelTimers();
  }

  double _calculateProgress(Timer timer) {
    double progress = timer.tick / smoothnessConstant;

    if (progress > 1) return 1;
    if (progress < 0) return 0;
    return progress;
  }

  void _setProgressAndNotify(double value) {
    _progress = value;
    _progressController.add(null);
  }

  Future<void> _cancelStreams() async {
    if (!_progressController.isClosed) await _progressController.close();
    if (!_timeoutController.isClosed) await _timeoutController.close();
  }

  void _cancelTimers() {
    if (_timer?.isActive == true) _timer.cancel();
    if (_periodicTimer?.isActive == true) _periodicTimer.cancel();
  }

  static Duration _calculateTickPeriod(Duration duration) {
    double tickPeriodMs = duration.inMilliseconds / smoothnessConstant;
    return Duration(milliseconds: tickPeriodMs.toInt());
  }
}

然后你可以实现一个 CircularProgressIndicator 来监听来自 ProgressControllerStream:

class RestartableCircularProgressIndicator extends StatefulWidget {
  final ProgressController controller;
  final VoidCallback onTimeout;

  RestartableCircularProgressIndicator({
    Key key,
    @required this.controller,
    this.onTimeout,
  })  : assert(controller != null),
        super(key: key);

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

class _RestartableCircularProgressIndicatorState
    extends State<RestartableCircularProgressIndicator> {
  ProgressController get controller => widget.controller;

  VoidCallback get onTimeout => widget.onTimeout;

  @override
  void initState() {
    super.initState();
    controller.progressStream.listen((_) => updateState());
    controller.timeoutStream.listen((_) => onTimeout());
  }

  @override
  Widget build(BuildContext context) {
    return CircularProgressIndicator(
      value: controller.progress,
    );
  }

  void updateState() => setState(() {});
}

您还可以将 CircularProgressIndicator 的一些参数传递给 RestartableCircularProgressIndicator,这样您就可以对其进行自定义。

一个用法示例:

void main() => runApp(MyApp());

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  ProgressController controller;

  @override
  void initState() {
    super.initState();
    controller = ProgressController(
      duration: Duration(seconds: 5),
    );
  }

  @override
  void dispose() {
    controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              RestartableCircularProgressIndicator(
                controller: controller,
                onTimeout: () => print('timeout'),
              ),
              RaisedButton(
                onPressed: controller.start,
                child: Text('Start'),
              ),
              RaisedButton(
                onPressed: controller.restart,
                child: Text('Restart'),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

有一天我会把它转换成一个库,但在那之前我无法提供这段代码的测试和文档,所以如果你想了解这里发生了什么,你必须研究它(对不起...... ).

关于flutter - 在 flutter 中的 CircularProgressIndicator 上显示计时器进度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56853554/

相关文章:

dart - 如何在使用 canvas.drawLine() 打印多行时添加时间延迟

flutter - 我们可以在手机上通过 chrome 浏览器打开一个 Flutter Web 应用程序吗?

c - 如何在 C 中创建高级计数器?

java - 如何创建非持久性 EJB 3.1 计时器?

actionscript-3 - Flex播放一系列声音文件

php - 使用 php 和 jquery 上传进度条

android - flutter) 使用 firebase 时出现问题

flutter - 如何防止我的构建方法循环?

java - JavaFX-无法再次运行任务

javascript - 增加我的密码长度进度条