简体   繁体   English

颤振倒数计时器

[英]Flutter Countdown Timer

How can I do to put the value passed in the construction, to make a timer that rounds to the first decimal and shows at the child text of my RaisedButton?如何将传递的值放入构造中,制作一个四舍五入到第一个小数点并显示在我的 RaisedButton 的子文本中的计时器? I've tried but without luck.我试过但没有运气。 I manage to make work the callback function with a simple Timer but no periodic and with no update of value in real time in the text...我设法使用一个简单的 Timer 使回调函数工作,但没有周期性,也没有在文本中实时更新值......

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

class TimerButton extends StatefulWidget {
  final Duration timerTastoPremuto;


  TimerButton(this.timerTastoPremuto);

  @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: () {
          int _start = widget.timerTastoPremuto.inMilliseconds;

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

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

Here is an example using Timer.periodic :这是一个使用Timer.periodic的示例:

Countdown starts from 10 to 0 on button click :倒计时从100按钮单击开始:

import 'dart:async';

[...]

Timer _timer;
int _start = 10;

void startTimer() {
  const oneSec = const Duration(seconds: 1);
  _timer = new Timer.periodic(
    oneSec,
    (Timer timer) {
      if (_start == 0) {
        setState(() {
          timer.cancel();
        });
      } else {
        setState(() {
          _start--;
        });
      }
    },
  );
}

@override
void dispose() {
  _timer.cancel();
  super.dispose();
}

Widget build(BuildContext context) {
  return new Scaffold(
    appBar: AppBar(title: Text("Timer test")),
    body: Column(
      children: <Widget>[
        RaisedButton(
          onPressed: () {
            startTimer();
          },
          child: Text("start"),
        ),
        Text("$_start")
      ],
    ),
  );
}

Result :结果 :

Flutter 倒数计时器示例

You can also use the CountdownTimer class from the quiver.async library, usage is even simpler :您还可以使用quiver.async库中的CountdownTimer类,使用更加简单:

import 'package:quiver/async.dart';

[...]

int _start = 10;
int _current = 10;

void startTimer() {
  CountdownTimer countDownTimer = new CountdownTimer(
    new Duration(seconds: _start),
    new Duration(seconds: 1),
  );

  var sub = countDownTimer.listen(null);
  sub.onData((duration) {
    setState(() { _current = _start - duration.elapsed.inSeconds; });
  });

  sub.onDone(() {
    print("Done");
    sub.cancel();
  });
}

Widget build(BuildContext context) {
  return new Scaffold(
    appBar: AppBar(title: Text("Timer test")),
    body: Column(
      children: <Widget>[
        RaisedButton(
          onPressed: () {
            startTimer();
          },
          child: Text("start"),
        ),
        Text("$_current")
      ],
    ),
  );
}

EDIT : For the question in comments about button click behavior编辑:关于按钮点击行为的评论中的问题

With the above code which uses Timer.periodic , a new timer will indeed be started on each button click, and all these timers will update the same _start variable, resulting in a faster decreasing counter.使用上面使用Timer.periodic的代码,每次单击按钮时都会启动一个新的计时器,并且所有这些计时器将更新相同的_start变量,从而导致更快的递减计数器。

There are multiple solutions to change this behavior, depending on what you want to achieve :有多种解决方案可以改变这种行为,具体取决于您想要实现的目标:

  • disable the button once clicked so that the user could not disturb the countdown anymore (maybe enable it back once timer is cancelled)单击后禁用按钮,以便用户不再打扰倒计时(可能在取消计时器后将其重新启用)
  • wrap the Timer.periodic creation with a non null condition so that clicking the button multiple times has no effect用非空条件包装Timer.periodic创建,以便多次单击按钮无效
if (_timer != null) {
  _timer = new Timer.periodic(...);
}
  • cancel the timer and reset the countdown if you want to restart the timer on each click :如果要在每次单击时重新启动计时器,请取消计时器并重置倒计时:
if (_timer != null) {
  _timer.cancel();
  _start = 10;
}
_timer = new Timer.periodic(...);
  • if you want the button to act like a play/pause button :如果您希望按钮像播放/暂停按钮一样:
if (_timer != null) {
  _timer.cancel();
  _timer = null;
} else {
  _timer = new Timer.periodic(...);
}

You could also use this official async package which provides a RestartableTimer class which extends from Timer and adds the reset method.你也可以使用这个官方的异步包,它提供了一个从Timer扩展的RestartableTimer类并添加了reset方法。

So just call _timer.reset();所以只需调用_timer.reset(); on each button click.在每个按钮点击。

Finally, Codepen now supports Flutter !最后,Codepen 现在支持 Flutter! So here is a live example so that everyone can play with it : https://codepen.io/Yann39/pen/oNjrVOb所以这里是一个活生生的例子,这样每个人都可以玩它: https ://codepen.io/Yann39/pen/oNjrVOb

I have created a Generic Timer Widget which can be used to display any kind of timer and its flexible as well.我创建了一个通用计时器小部件,它可以用来显示任何类型的计时器,而且它也很灵活。

This Widget takes following properties此小部件具有以下属性

  1. secondsRemaining : duration for which timer needs to run in seconds secondsRemaining :计时器需要运行的持续时间(以秒为单位)
  2. whenTimeExpires : what action needs to be performed if timer finished whenTimeExpires : 如果计时器完成,需要执行什么操作
  3. countDownStyle : any kind of style which you want to give to timer countDownStyle : 你想给定时器的任何样式
  4. countDownFormatter : the way user wants to display the count down timer eg hh mm ss string like 01 hours: 20 minutes: 45 seconds countDownFormatter :用户想要显示倒数计时器的方式,例如hh mm ss字符串,如01 hours: 20 minutes: 45 seconds

you can provide a default formatter ( formatHHMMSS ) in case you don't want to supply it from every place.您可以提供一个默认格式化程序 ( formatHHMMSS ),以防您不想从每个地方提供它。

// provide implementation for this - formatHHMMSS(duration.inSeconds); // 为此提供实现 - formatHHMMSS(duration.inSeconds); or use below one which I have provided.或使用我提供的以下一个。

import 'package:flutter/material.dart';
class CountDownTimer extends StatefulWidget {
  const CountDownTimer({
    Key key,
    int secondsRemaining,
    this.countDownTimerStyle,
    this.whenTimeExpires,
    this.countDownFormatter,
  })  : secondsRemaining = secondsRemaining,
        super(key: key);

  final int secondsRemaining;
  final Function whenTimeExpires;
  final Function countDownFormatter;
  final TextStyle countDownTimerStyle;

  State createState() => new _CountDownTimerState();
}

class _CountDownTimerState extends State<CountDownTimer>
    with TickerProviderStateMixin {
  AnimationController _controller;
  Duration duration;

  String get timerDisplayString {
    Duration duration = _controller.duration * _controller.value;
    return widget.countDownFormatter != null
        ? widget.countDownFormatter(duration.inSeconds)
        : formatHHMMSS(duration.inSeconds);
      // In case user doesn't provide formatter use the default one
     // for that create a method which will be called formatHHMMSS or whatever you like
  }

  @override
  void initState() {
    super.initState();
    duration = new Duration(seconds: widget.secondsRemaining);
    _controller = new AnimationController(
      vsync: this,
      duration: duration,
    );
    _controller.reverse(from: widget.secondsRemaining.toDouble());
    _controller.addStatusListener((status) {
      if (status == AnimationStatus.completed || status == AnimationStatus.dismissed) {
        widget.whenTimeExpires();
      }
    });
  }

  @override
  void didUpdateWidget(CountDownTimer oldWidget) {
    if (widget.secondsRemaining != oldWidget.secondsRemaining) {
      setState(() {
        duration = new Duration(seconds: widget.secondsRemaining);
        _controller.dispose();
        _controller = new AnimationController(
          vsync: this,
          duration: duration,
        );
        _controller.reverse(from: widget.secondsRemaining.toDouble());
        _controller.addStatusListener((status) {
          if (status == AnimationStatus.completed) {
            widget.whenTimeExpires();
          } else if (status == AnimationStatus.dismissed) {
            print("Animation Complete");
          }
        });
      });
    }
  }

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

  @override
  Widget build(BuildContext context) {
    return new Center(
        child: AnimatedBuilder(
            animation: _controller,
            builder: (_, Widget child) {
              return Text(
                timerDisplayString,
                style: widget.countDownTimerStyle,
              );
            }));
  }
}

Usage:用法:

 Container(
       width: 60.0,
       padding: EdgeInsets.only(top: 3.0, right: 4.0),
         child: CountDownTimer(
           secondsRemaining: 30,
           whenTimeExpires: () {
              setState(() {
                hasTimerStopped = true;
              });
            },
            countDownTimerStyle: TextStyle(
                color: Color(0XFFf5a623),
                fontSize: 17.0,
                height: 1.2,
            ),
          ),
        )

example for formatHHMMSS :格式HHMMSS示例:

String formatHHMMSS(int seconds) {
  int hours = (seconds / 3600).truncate();
  seconds = (seconds % 3600).truncate();
  int minutes = (seconds / 60).truncate();

  String hoursStr = (hours).toString().padLeft(2, '0');
  String minutesStr = (minutes).toString().padLeft(2, '0');
  String secondsStr = (seconds % 60).toString().padLeft(2, '0');

  if (hours == 0) {
    return "$minutesStr:$secondsStr";
  }

  return "$hoursStr:$minutesStr:$secondsStr";
}

Null Safe Version of the Above Code上述代码的空安全版本

import 'package:flutter/material.dart';

class CountDownTimer extends StatefulWidget {
  const CountDownTimer({
    Key? key,
    required this.secondsRemaining,
    required this.whenTimeExpires,
    this.countDownFormatter,
    this.countDownTimerStyle,
  }) : super(key: key);

  final int secondsRemaining;
  final VoidCallback whenTimeExpires;
  final TextStyle? countDownTimerStyle;
  final Function(int seconds)? countDownFormatter;

  @override
  State createState() => _CountDownTimerState();
}

class _CountDownTimerState extends State<CountDownTimer>
    with TickerProviderStateMixin {
  late final AnimationController _controller;
  late final Duration duration;

  String get timerDisplayString {
    final duration = _controller.duration! * _controller.value;
    if (widget.countDownFormatter != null) {
      return widget.countDownFormatter!(duration.inSeconds) as String;
    } else {
      return formatHHMMSS(duration.inSeconds);
    }
  }

  String formatHHMMSS(int seconds) {
    final hours = (seconds / 3600).truncate();
    seconds = (seconds % 3600).truncate();
    final minutes = (seconds / 60).truncate();

    final hoursStr = (hours).toString().padLeft(2, '0');
    final minutesStr = (minutes).toString().padLeft(2, '0');
    final secondsStr = (seconds % 60).toString().padLeft(2, '0');

    if (hours == 0) {
      return '$minutesStr:$secondsStr';
    }

    return '$hoursStr:$minutesStr:$secondsStr';
  }

  @override
  void initState() {
    super.initState();
    duration = Duration(seconds: widget.secondsRemaining);
    _controller = AnimationController(
      vsync: this,
      duration: duration,
    );
    _controller
      ..reverse(from: widget.secondsRemaining.toDouble())
      ..addStatusListener((status) {
        if (status == AnimationStatus.completed ||
            status == AnimationStatus.dismissed) {
          widget.whenTimeExpires();
        }
      });
  }

  @override
  void didUpdateWidget(CountDownTimer oldWidget) {
    super.didUpdateWidget(oldWidget);
    if (widget.secondsRemaining != oldWidget.secondsRemaining) {
      setState(() {
        duration = Duration(seconds: widget.secondsRemaining);
        _controller.dispose();
        _controller = AnimationController(
          vsync: this,
          duration: duration,
        );
        _controller
          ..reverse(from: widget.secondsRemaining.toDouble())
          ..addStatusListener((status) {
            if (status == AnimationStatus.completed) {
              widget.whenTimeExpires();
            }
          });
      });
    }
  }

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

  @override
  Widget build(BuildContext context) {
    return Center(
      child: AnimatedBuilder(
        animation: _controller,
        builder: (_, Widget? child) {
          return Text(
            timerDisplayString,
            style: widget.countDownTimerStyle,
          );
        },
      ),
    );
  }
}

Little late to the party but why don't you guys try animation.No I am not telling you to manage animation controllers and disposing them off and all that stuff, there's a built-in widget for that called TweenAnimationBuilder .派对迟到了,但你们为什么不尝试动画。不,我不是在告诉你管理动画控制器并将它们处理掉以及所有这些东西,有一个名为TweenAnimationBuilder的内置小部件。 You can animate between values of any type, here's an example with a Duration class您可以在任何类型的值之间进行动画处理,这是一个 Duration 类的示例

TweenAnimationBuilder<Duration>(
  duration: Duration(minutes: 3),
  tween: Tween(begin: Duration(minutes: 3), end: Duration.zero),
  onEnd: () {
    print('Timer ended');
  },
  builder: (BuildContext context, Duration value, Widget? child) {
    final minutes = value.inMinutes;
    final seconds = value.inSeconds % 60;
    return Padding(
      padding: const EdgeInsets.symmetric(vertical: 5),
      child: Text('$minutes:$seconds',
               textAlign: TextAlign.center,
               style: TextStyle(
               color: Colors.black,
               fontWeight: FontWeight.bold,
               fontSize: 30)));
    }),

and You also get onEnd call back which notifies you when the animation completes;并且您还会收到 onEnd 回调,它会在动画完成时通知您;

here's the output这是输出

Here is my Timer widget, not related to the Question but may help someone.这是我的计时器小部件,与问题无关,但可能对某人有所帮助。

import 'dart:async';

import 'package:flutter/material.dart';

class OtpTimer extends StatefulWidget {
  @override
  _OtpTimerState createState() => _OtpTimerState();
}

class _OtpTimerState extends State<OtpTimer> {
  final interval = const Duration(seconds: 1);

  final int timerMaxSeconds = 60;

  int currentSeconds = 0;

  String get timerText =>
      '${((timerMaxSeconds - currentSeconds) ~/ 60).toString().padLeft(2, '0')}: ${((timerMaxSeconds - currentSeconds) % 60).toString().padLeft(2, '0')}';

  startTimeout([int milliseconds]) {
    var duration = interval;
    Timer.periodic(duration, (timer) {
      setState(() {
        print(timer.tick);
        currentSeconds = timer.tick;
        if (timer.tick >= timerMaxSeconds) timer.cancel();
      });
    });
  }

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

  @override
  Widget build(BuildContext context) {
    return Row(
      mainAxisSize: MainAxisSize.min,
      children: <Widget>[
        Icon(Icons.timer),
        SizedBox(
          width: 5,
        ),
        Text(timerText)
      ],
    );
  }
}

You will get something like this你会得到这样的东西

在此处输入图像描述

doesnt directly answer your question.不直接回答你的问题。 But helpful for those who want to start something after some time.但对那些想在一段时间后开始做某事的人很有帮助。

Future.delayed(Duration(seconds: 1), () {
            print('yo hey');
          });

If all you need is a simple countdown timer, this is a good alternative instead of installing a package.如果您只需要一个简单的倒数计时器,那么这是一个不错的选择,而不是安装软件包。 Happy coding!快乐编码!

countDownTimer() async {
 int timerCount;
 for (int x = 5; x > 0; x--) {
   await Future.delayed(Duration(seconds: 1)).then((_) {
     setState(() {
       timerCount -= 1;
    });
  });
 }
}

I'm using https://pub.dev/packages/flutter_countdown_timer我正在使用https://pub.dev/packages/flutter_countdown_timer

dependencies: flutter_countdown_timer: ^1.0.0依赖项:flutter_countdown_timer:^1.0.0

$ flutter pub get $颤振酒吧得到

CountdownTimer(endTime: 1594829147719)

1594829147719 is your timestamp in milliseconds 1594829147719 是您的时间戳,以毫秒为单位

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

class CustomTimer extends StatefulWidget {
  @override
  _CustomTimerState createState() => _CustomTimerState();
}

class _CustomTimerState extends State<CustomTimer> {
  final _maxSeconds = 61;
  int _currentSecond = 0;
  Timer _timer;

  String get _timerText {
    final secondsPerMinute = 60;
    final secondsLeft = _maxSeconds - _currentSecond;

    final formattedMinutesLeft =
        (secondsLeft ~/ secondsPerMinute).toString().padLeft(2, '0');
    final formattedSecondsLeft =
        (secondsLeft % secondsPerMinute).toString().padLeft(2, '0');

    print('$formattedMinutesLeft : $formattedSecondsLeft');
    return '$formattedMinutesLeft : $formattedSecondsLeft';
  }

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

  @override
  void dispose() {
    _timer.cancel();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Row(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Icon(Icons.timer),
            Text(_timerText),
          ],
        ),
      ),
    );
  }

  void _startTimer() {
    final duration = Duration(seconds: 1);
    _timer = Timer.periodic(duration, (Timer timer) {
      setState(() {
        _currentSecond = timer.tick;
        if (timer.tick >= _maxSeconds) timer.cancel();
      });
    });
  }
}

I've Created a amazing timer without any plugin, here you can also get count down timer.我创建了一个没有任何插件的惊人计时器,在这里你也可以得到倒数计时器。 And don't forget to stop the timer on back pressed.并且不要忘记在按下后停止计时器。

Here is the link of my timer full Project.这是我的计时器完整项目的链接。 * Hope this will help someone. *希望这会对某人有所帮助。 Thank you.谢谢你。 * *

在此处输入图像描述

   import 'dart:async';

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: AttendanceScreen(),
    );
  }
}

class AttendanceScreen extends StatefulWidget {
  AttendanceScreen();

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

class _AttendanceScreenState extends State<AttendanceScreen> {
  static var countdownDuration = Duration(minutes: 10);
  static var countdownDuration1 = Duration(minutes: 10);
  Duration duration = Duration();
  Duration duration1 = Duration();
  Timer? timer;
  Timer? timer1;
  bool countDown = true;
  bool countDown1 = true;

  @override
  void initState() {
    var hours;
    var mints;
    var secs;
    hours = int.parse("00");
    mints = int.parse("00");
    secs = int.parse("00");
    countdownDuration = Duration(hours: hours, minutes: mints, seconds: secs);
    startTimer();
    reset();
    var hours1;
    var mints1;
    var secs1;
    hours1 = int.parse("10");
    mints1 = int.parse("00");
    secs1 = int.parse("00");
    countdownDuration1 =
        Duration(hours: hours1, minutes: mints1, seconds: secs1);
    startTimer1();
    reset1();
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return WillPopScope(
      onWillPop: _onWillPop,
      child: Scaffold(
        appBar: AppBar(
          title: Text("Timer Example"),
          leading: IconButton(
            icon: Icon(Icons.arrow_back_ios),
            color: Colors.white,
            onPressed: () {
              _onWillPop();
            },
          ),
        ),
        body: Container(
          color: Colors.black12,
          width: double.infinity,
          child: Column(
              mainAxisAlignment: MainAxisAlignment.start,
              crossAxisAlignment: CrossAxisAlignment.center,
              children: [
                SizedBox(
                  height: 20,
                ),
                Text(
                  "Timer",
                  style: TextStyle(fontSize: 25),
                ),
                Container(
                    margin: EdgeInsets.only(top: 30, bottom: 30),
                    child: buildTime()),
                SizedBox(
                  height: 20,
                ),
                Text(
                  "Count down timer",
                  style: TextStyle(fontSize: 25),
                ),
                Container(
                    margin: EdgeInsets.only(top: 30, bottom: 30),
                    child: buildTime1()),
              ]),
        ),
      ),
    );
  }

  Future<bool> _onWillPop() async {
    final isRunning = timer == null ? false : timer!.isActive;
    if (isRunning) {
      timer!.cancel();
    }
    Navigator.of(context, rootNavigator: true).pop(context);
    return true;
  }

  void reset() {
    if (countDown) {
      setState(() => duration = countdownDuration);
    } else {
      setState(() => duration = Duration());
    }
  }

  void reset1() {
    if (countDown) {
      setState(() => duration1 = countdownDuration1);
    } else {
      setState(() => duration1 = Duration());
    }
  }

  void startTimer() {
    timer = Timer.periodic(Duration(seconds: 1), (_) => addTime());
  }

  void startTimer1() {
    timer = Timer.periodic(Duration(seconds: 1), (_) => addTime1());
  }

  void addTime() {
    final addSeconds = 1;
    setState(() {
      final seconds = duration.inSeconds + addSeconds;
      if (seconds < 0) {
        timer?.cancel();
      } else {
        duration = Duration(seconds: seconds);
      }
    });
  }

  void addTime1() {
    final addSeconds = 1;
    setState(() {
      final seconds = duration1.inSeconds - addSeconds;
      if (seconds < 0) {
        timer1?.cancel();
      } else {
        duration1 = Duration(seconds: seconds);
      }
    });
  }

  Widget buildTime() {
    String twoDigits(int n) => n.toString().padLeft(2, '0');
    final hours = twoDigits(duration.inHours);
    final minutes = twoDigits(duration.inMinutes.remainder(60));
    final seconds = twoDigits(duration.inSeconds.remainder(60));
    return Row(mainAxisAlignment: MainAxisAlignment.center, children: [
      buildTimeCard(time: hours, header: 'HOURS'),
      SizedBox(
        width: 8,
      ),
      buildTimeCard(time: minutes, header: 'MINUTES'),
      SizedBox(
        width: 8,
      ),
      buildTimeCard(time: seconds, header: 'SECONDS'),
    ]);
  }

  Widget buildTime1() {
    String twoDigits(int n) => n.toString().padLeft(2, '0');
    final hours = twoDigits(duration1.inHours);
    final minutes = twoDigits(duration1.inMinutes.remainder(60));
    final seconds = twoDigits(duration1.inSeconds.remainder(60));
    return Row(mainAxisAlignment: MainAxisAlignment.center, children: [
      buildTimeCard(time: hours, header: 'HOURS'),
      SizedBox(
        width: 8,
      ),
      buildTimeCard(time: minutes, header: 'MINUTES'),
      SizedBox(
        width: 8,
      ),
      buildTimeCard(time: seconds, header: 'SECONDS'),
    ]);
  }

  Widget buildTimeCard({required String time, required String header}) =>
      Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          Container(
            padding: EdgeInsets.all(8),
            decoration: BoxDecoration(
                color: Colors.white, borderRadius: BorderRadius.circular(20)),
            child: Text(
              time,
              style: TextStyle(
                  fontWeight: FontWeight.bold,
                  color: Colors.black,
                  fontSize: 50),
            ),
          ),
          SizedBox(
            height: 24,
          ),
          Text(header, style: TextStyle(color: Colors.black45)),
        ],
      );
}

Many answer already provided.已经提供了许多答案。 I suggest a shortcut way-我建议一种快捷方式-

Use this package Custom_timer使用这个包Custom_timer

Add this to your package's pubspec.yaml file:将此添加到包的 pubspec.yaml 文件中:

dependencies:
  custom_timer: ^0.0.3 

(use latest version) (使用最新版本)

and very simple to implement并且实现起来非常简单

@override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        appBar: AppBar(
          title: Text("CustomTimer example"),
        ),
        body: Center(
          child: CustomTimer(
            from: Duration(hours: 12),
            to: Duration(hours: 0),
            onBuildAction: CustomTimerAction.auto_start,
            builder: (CustomTimerRemainingTime remaining) {
              return Text(
                "${remaining.hours}:${remaining.minutes}:${remaining.seconds}",
                style: TextStyle(fontSize: 30.0),
              );
            },
          ),
        ),
      ),
    );
  }

You can use this plugin timer_builder你可以使用这个插件timer_builder

timer_builder widget that rebuilds itself on scheduled, periodic, or dynamically generated time events. timer_builder 小部件,它在计划的、定期的或动态生成的时间事件上重建自己。

Examples例子

Periodic rebuild定期重建

import 'package:timer_builder/timer_builder.dart';

class ClockWidget extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return TimerBuilder.periodic(Duration(seconds: 1),
      builder: (context) {
        return Text("${DateTime.now()}");
      }
    );
  }
  
}

Rebuild on a schedule按计划重建

import 'package:timer_builder/timer_builder.dart';

class StatusIndicator extends StatelessWidget {

  final DateTime startTime;
  final DateTime endTime;
  
  StatusIndicator(this.startTime, this.endTime);
  
  @override
  Widget build(BuildContext context) {
    return TimerBuilder.scheduled([startTime, endTime],
      builder: (context) {
        final now = DateTime.now();
        final started = now.compareTo(startTime) >= 0;
        final ended = now.compareTo(endTime) >= 0;
        return Text(started ? ended ? "Ended": "Started": "Not Started");
      }
    );
  }
  
}

在此处输入图片说明

For showing your total seconds in this format hh:mm:ss, you can use below method:要以这种格式 hh:mm:ss 显示您的总秒数,您可以使用以下方法:

 String getDuration(int totalSeconds) {
    String seconds = (totalSeconds % 60).toInt().toString().padLeft(2, '0');
    String minutes =
   ((totalSeconds / 60) % 60).toInt().toString().padLeft(2, '0');
   String hours = (totalSeconds ~/ 3600).toString().padLeft(2, '0');

   return "$hours\:$minutes\:$seconds";


}
import 'package:rxdart/rxdart.dart';

final BehaviorSubject<int> resendTimeController = BehaviorSubject<int>();
static const timerDuration = 90;
int resendTimer = 0;
Timer? timer;

void startTimer() {
  timer?.cancel();
  resendTimer = timerDuration;

  timer = Timer.periodic(const Duration(seconds: 1), (timer) {
    if (resendTimer > 0) {
      resendTimer--;
      resendTimeController.add(resendTimer);

      if (resendTimer == 0) {
        timer.cancel();
      }
    }
  });
}
and use intl this

StreamBuilder<int>(
  stream: _bloc.resendTimeController,
  builder: (context, snapshot) {
    if (!snapshot.hasData) {
      return Container();
    }

    final DateTime date = DateTime.fromMillisecondsSinceEpoch(snapshot.data! * 1000);

    return GestureDetector(
      onTap: () {
        if (snapshot.data == 0) {
          _bloc.resendCode();
        }
      },
      child: Text(
        snapshot.data! > 0 ? 'Resend code ${DateFormat('mm:ss').format(date)}' : 'Resend SMS',
      ),
    );
  },
),
import 'package:async/async.dart';
    
late CancelableOperation? cancellableOperation;
int counter = 5;

StatefulBuilder(
   builder: (context, setState) {
              if (counter > 0) {
                cancellableOperation = CancelableOperation.fromFuture(
                  Future.delayed(const Duration(seconds: 1)),
                  onCancel: () => {},
                );
                cancellableOperation?.value.whenComplete(() => setState(() => counter--));
                return buildButton(
                  text: 'Wait($counter)',
                  textColor: getTextColor,
                  backgroundColor: Colors.grey.withOpacity(0.5),
                  onPressed: () {},
                );
              }
              return buildButton(
                text: 'Complete',
                textColor: Colors.green,
                backgroundColor: Colors.greenAccent.withOpacity(0.5),
                onPressed: () {},
              );
            },
          )

I did something like this for my dialog's complete button.我为对话框的完成按钮做了类似的事情。 It counts for 5 seconds before to show complete button.它会在显示完成按钮之前计数 5 秒。 But do not forget to call cancellableOperation?.cancel() if you close the dialog or page before counting complete.但是,如果在计数完成之前关闭对话框或页面,请不要忘记调用cancellableOperation?.cancel()

Countdown timer in one line倒数计时器在一行

CountdownTimer(Duration(seconds: 5), Duration(seconds: 1)).listen((data){
})..onData((data){
  print('data $data');
})..onDone((){
  print('onDone.........');
});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM