【问题标题】:Timer with update to the first decimal更新到小数点后的计时器
【发布时间】:2019-02-15 17:27:18
【问题描述】:

我正在尝试让这个计时器工作。抱歉造成混乱,但尝试了很多。制作它的最佳方法是什么?我开始感到困惑。我想让那个时间 = 30 上升到 0,更新为 0.1,然后播放警报声。

 import 'package:flutter/material.dart';
 import 'dart:ui';
 import 'dart:async';

 class TimerButton extends StatefulWidget {
   final int time = 30;


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

 class _TimerButtonState extends State<TimerButton> {
   @override
   Widget build(BuildContext context) {

     return Container(
       margin: EdgeInsets.all(5.0),
       height: 135.0,
       width: 135.0,
       child: new RaisedButton(
        elevation: 100.0,
         color: Colors.white.withOpacity(.8),
         highlightElevation: 0.0,
         onPressed: () {
           startTimer(widget.time);

         };
         splashColor: Colors.red,
         highlightColor: Colors.red,
         //shape: RoundedRectangleBorder e tutto il resto uguale
         shape: BeveledRectangleBorder(
             side: BorderSide(color: Colors.black, width: 2.5),
             borderRadius: new BorderRadius.circular(15.0)),
         child: new Text(
           "${_start}",
           style: new TextStyle(fontFamily: "Minim", fontSize: 50.0),
         ),
       ),
     );
   }
 }

 int startTimer(int time){
   Timer _timer;
   int _start = time;

   const oneSec = const Duration(milliseconds: 100);
   _timer = new Timer.periodic(oneSec, (Timer timer) {
     _TimerButtonState().setState((){
       if (_start < 0.1) {
         timer.cancel();
       } else {
         _start = _start - 100;
       }
     });
   });

 }

【问题讨论】:

    标签: timer dart flutter setstate


    【解决方案1】:
    import 'package:flutter/material.dart';
    import 'dart:ui';
    import 'dart:async';
    
    const oneTick = const Duration(milliseconds: 100);
    
    class TimerButton extends StatefulWidget {
      /// desired duration in seconds
      final int time;
    
      TimerButton({Key key, this.time: 30}): super(key:key);
    
      @override
      TimerButtonState createState() => _TimerButtonState();
    }
    
    class TimerButtonState extends State<TimerButton>
        with SingleTickerProviderStateMixin {
      /// timer instance
      Timer _timer;
    
      /// holds number of millis till end
      int _millisLeft;
    
      /// holds total desired duration
      Duration _totalDuration;
    
      @override
      void initState() {
        // create convertable duration object with desired number of seconds
        _totalDuration = Duration(seconds: widget.time);
    
        resetTimer();
      }
    
      @override
      Widget build(BuildContext context) {
        return Container(
          margin: EdgeInsets.all(5.0),
          height: 135.0,
          width: 135.0,
          child: new RaisedButton(
            elevation: 100.0,
            color: Colors.white.withOpacity(.8),
            highlightElevation: 0.0,
            onPressed: () {
              // reset
              resetTimer();
              startTimer();
            },
            splashColor: Colors.red,
            highlightColor: Colors.red,
            //shape: RoundedRectangleBorder e tutto il resto uguale
            shape: BeveledRectangleBorder(
                side: BorderSide(color: Colors.black, width: 2.5),
                borderRadius: new BorderRadius.circular(15.0)),
            child: new Text(
              formatTime(_millisLeft),
              style: new TextStyle(fontFamily: "Minim", fontSize: 50.0),
            ),
          ),
        );
      }
    
      void resetTimer() {
        setState(() {
          // cancel if any
          _timer?.cancel();
          // reset value to begin from
          _millisLeft = _totalDuration.inMilliseconds;
        });
      }
    
      void startTimer() {
        setState(() {
          _timer = new Timer.periodic(oneTick, onTick);
        });
      }
    
      void onTick(Timer timer) {
        print(_millisLeft);
    
        setState(() {
          // stop when lower then 1 tick duration
          if (_millisLeft < oneTick.inMilliseconds) {
            timer.cancel();
          } else {
            // subtract one tick
            _millisLeft -= oneTick.inMilliseconds;
          }
        });
      }
    
      /// divide by 1000 to сonvert millis to seconds (in double precision),
      /// then use toStringAsFixed(number of precision digits after comma)
      String formatTime(int ms) {
        return (ms / 1000).toStringAsFixed(2);
      }
    }
    

    用法

    TimerButton()
    

    TimerButton(seconds:420)
    

    添加以回答您的评论

    1) 为了能够从外部重置它: 在单独的文件中,例如keys.dart 注册一个全局密钥(每个应用注册一次,我的意思是不要重复这一行)

    GlobalKey<TimerButtonState> timerKey = GlobalKey<TimerButtonState>();
    

    然后,当您创建计时器时,将此密钥传递给它

    ... your screen or whatever
    import '../keys.dart'
    ...
    TimerButton(key: timerKey, time:50)
    ...
    onClick: timerKey.currentState.resetTimer //shorthand syntax
    onClick: () {
            timerKey.currentState.resetTimer();
            }  // for sure
    

    2) 将值从小部件传递给父级:

    class TimerButton extends StatefulWidget {
      /// desired duration in seconds
      final int time;
      final Function(Duration) onTicked;
    
    
      TimerButton({Key key, this.time: 30, this.onTicked}): super(key:key);
    
      @override
      TimerButtonState createState() => _TimerButtonState();
    }
    ...
    //in state:
    ...
    void onTick(Timer timer) {
        print(_millisLeft);
    
        setState(() {
          if (_millisLeft < oneTick.inMilliseconds) {
            timer.cancel();
            widget.onStopped();  // tell whoever interested that it's stopped
          } else {
            // subtract one tick
            _millisLeft -= oneTick.inMilliseconds;
            widget.onTicked(_millisLeft);  // tell about updates
          }
        });
      }
    // in parent:
    ...
    TimerButton(key: timerKey,
                time:50,
                onStop: (){ parent.doSmthOnStop();},
                onTicked: (int millisLeft) {
                             setState((){
                             parentStateVariable = millisLeft;
                          });
                      })
    ...
    

    【讨论】:

    • 谢谢。我设法做到了,但这要干净得多。我会好好研究你的代码。但是我遇到的一个问题是我想从这个类之外,从另一个类调用重置计时器。如何在 _TimerButtonState 之外传递函数?我已经看到要传递数据,我必须使用 initState 然后使用 widget.variable 例如。但我不知道如何传递这些值或我在该类中创建的任何函数,以便从外部调用。
    • 更新了答案。 (要使用密钥,您的州名不应以下划线开头。
    • 啊好的。只是我知道如果我没记错的话,加上下划线意味着该类是私有的,但是我认为有某种常见的做法可以使该类保持私有并以某种方式访问​​这些变量。例如,类外部的非私有函数可以访问这些变量,但类本身仍然是私有的,就像常用的一样。我对么?还是不带下划线?
    • 对,你可以在同一个文件中创建一个带有状态的密钥并将 _State 保留为私有,不确定它是否有任何区别,因为你的状态已经通过密钥公开了,我只是更喜欢将所有密钥存储在单独的文件:)
    • 小问题。您会看到我在 RaisedButton 小部件中显示了一个计时器。我在主页中创建了该小部件的 6 个实例。每个人的开始时间都不一样。直到现在一切都好。如何分别启动或停止每一项?或者我必须为每个人创建一个密钥。我想让每次只有一个计时器处于活动状态。如果你按下另一个,旧的按下并且活动停止并重置,最后按下的只是正常启动。如果您只能解释最佳工作流程而不是代码。如果可以,代码会更好,但这足以开始处理它
    猜你喜欢
    • 2015-06-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多