【问题标题】:Show timer progress on a CircularProgressIndicator in flutter在颤动的 CircularProgressIndicator 上显示计时器进度
【发布时间】:2019-07-02 13:25:39
【问题描述】:

我使用RestartableTimerTimer 的子类)作为倒数计时器,以在一定时间后将人们“踢出”表单。

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

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

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

  • 我不知道如何每隔 x 毫秒检查一次计时器进度。我怎样才能做到这一点?我不需要 copy-pasta 代码,而是更多“我应该选择什么对象/哪个方向”?

  • 没有实现以tick为单位的计时器进度(NotImplementedException);有没有办法在其他地方有等价物?除了那部分之外,那个对象对我来说真的很好用。

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

【问题讨论】:

    标签: flutter timer progress-bar


    【解决方案1】:

    在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 来监听来自ProgressControllerStreams:

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

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

    【讨论】:

    • 它是我需要的一个非常好的基础;我很舒服,可以理解它。明天白天会检查这个。现在我发现在一个单独的类中使用 Streambuilder + 秒表 + 计时器。它有效,但我还没有觉得它超级干净。
    猜你喜欢
    • 2021-11-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-30
    • 1970-01-01
    • 2019-01-10
    • 1970-01-01
    • 2020-08-10
    相关资源
    最近更新 更多