首页 > 解决方案 > 更新到小数点后的计时器

问题描述

我试图让这个计时器工作。抱歉造成混乱,但尝试了很多。制作它的最佳方法是什么?我开始感到困惑。我想让那个时间 = 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;
       }
     });
   });

 }

标签: timerdartfluttersetstate

解决方案


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;
                      });
                  })
...

推荐阅读