繁体   English   中英

颤振倒数计时器

[英]Flutter Countdown Timer

如何将传递的值放入构造中,制作一个四舍五入到第一个小数点并显示在我的 RaisedButton 的子文本中的计时器? 我试过但没有运气。 我设法使用一个简单的 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),
        ),
      ),
    );
  }
}

这是一个使用Timer.periodic的示例:

倒计时从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")
      ],
    ),
  );
}

结果 :

Flutter 倒数计时器示例

您还可以使用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")
      ],
    ),
  );
}

编辑:关于按钮点击行为的评论中的问题

使用上面使用Timer.periodic的代码,每次单击按钮时都会启动一个新的计时器,并且所有这些计时器将更新相同的_start变量,从而导致更快的递减计数器。

有多种解决方案可以改变这种行为,具体取决于您想要实现的目标:

  • 单击后禁用按钮,以便用户不再打扰倒计时(可能在取消计时器后将其重新启用)
  • 用非空条件包装Timer.periodic创建,以便多次单击按钮无效
if (_timer != null) {
  _timer = new Timer.periodic(...);
}
  • 如果要在每次单击时重新启动计时器,请取消计时器并重置倒计时:
if (_timer != null) {
  _timer.cancel();
  _start = 10;
}
_timer = new Timer.periodic(...);
  • 如果您希望按钮像播放/暂停按钮一样:
if (_timer != null) {
  _timer.cancel();
  _timer = null;
} else {
  _timer = new Timer.periodic(...);
}

你也可以使用这个官方的异步包,它提供了一个从Timer扩展的RestartableTimer类并添加了reset方法。

所以只需调用_timer.reset(); 在每个按钮点击。

最后,Codepen 现在支持 Flutter! 所以这里是一个活生生的例子,这样每个人都可以玩它: https ://codepen.io/Yann39/pen/oNjrVOb

我创建了一个通用计时器小部件,它可以用来显示任何类型的计时器,而且它也很灵活。

此小部件具有以下属性

  1. secondsRemaining :计时器需要运行的持续时间(以秒为单位)
  2. whenTimeExpires : 如果计时器完成,需要执行什么操作
  3. countDownStyle : 你想给定时器的任何样式
  4. countDownFormatter :用户想要显示倒数计时器的方式,例如hh mm ss字符串,如01 hours: 20 minutes: 45 seconds

您可以提供一个默认格式化程序 ( formatHHMMSS ),以防您不想从每个地方提供它。

// 为此提供实现 - formatHHMMSS(duration.inSeconds); 或使用我提供的以下一个。

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

用法:

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

格式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";
}

上述代码的空安全版本

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

派对迟到了,但你们为什么不尝试动画。不,我不是在告诉你管理动画控制器并将它们处理掉以及所有这些东西,有一个名为TweenAnimationBuilder的内置小部件。 您可以在任何类型的值之间进行动画处理,这是一个 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)));
    }),

并且您还会收到 onEnd 回调,它会在动画完成时通知您;

这是输出

这是我的计时器小部件,与问题无关,但可能对某人有所帮助。

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

你会得到这样的东西

在此处输入图像描述

不直接回答你的问题。 但对那些想在一段时间后开始做某事的人很有帮助。

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

如果您只需要一个简单的倒数计时器,那么这是一个不错的选择,而不是安装软件包。 快乐编码!

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

我正在使用https://pub.dev/packages/flutter_countdown_timer

依赖项:flutter_countdown_timer:^1.0.0

$颤振酒吧得到

CountdownTimer(endTime: 1594829147719)

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

我创建了一个没有任何插件的惊人计时器,在这里你也可以得到倒数计时器。 并且不要忘记在按下后停止计时器。

这是我的计时器完整项目的链接。 *希望这会对某人有所帮助。 谢谢你。 *

在此处输入图像描述

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

已经提供了许多答案。 我建议一种快捷方式-

使用这个包Custom_timer

将此添加到包的 pubspec.yaml 文件中:

dependencies:
  custom_timer: ^0.0.3 

(使用最新版本)

并且实现起来非常简单

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

你可以使用这个插件timer_builder

timer_builder 小部件,它在计划的、定期的或动态生成的时间事件上重建自己。

例子

定期重建

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()}");
      }
    );
  }
  
}

按计划重建

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

在此处输入图片说明

要以这种格式 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: () {},
              );
            },
          )

我为对话框的完成按钮做了类似的事情。 它会在显示完成按钮之前计数 5 秒。 但是,如果在计数完成之前关闭对话框或页面,请不要忘记调用cancellableOperation?.cancel()

倒数计时器在一行

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