创建一个倒计时器,为列表中的每个值每5秒打印一次剩余时间

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了创建一个倒计时器,为列表中的每个值每5秒打印一次剩余时间相关的知识,希望对你有一定的参考价值。

我正在尝试在Flutter中创建倒数计时器,每隔5秒打印一次剩余时间,直到计时器用完,然后为值列表中的下一个值运行相同的倒计时器。

下面的递归函数变得接近,但它会在转到List中的下一个值之前等待“迭代”,即使该Timer的剩余时间较少。

import 'dart:async';

Future main() async {
  final _sequence = [21, 10, 8];
  final _iteration = 5;

  void _countdown(seq) async {
    if (seq.length > 0) {
      var duration = seq[0];
      print('Starting at $duration');
      Timer.periodic(Duration(seconds: _iteration), (timer) {
        var remaining = duration - timer.tick * _iteration;
        if (remaining >= 0) {
          print('$duration, $remaining');
        } else {
          timer.cancel();
          _countdown(seq.sublist(1));
        }
      });
    }
  }

  _countdown(_sequence);
}

每次运行时,持续时间由_sequence列表中的值定义。

即使使用CountdownTimer(而不是Timer.periodic)也有同样的问题,当剩余的值小于迭代时等待太长时间:

import 'package:quiver/async.dart';

main() {
  final _sequence = [21, 10, 8];
  final _iteration = 5;

  void _countdown(seq) {
    if (seq.length > 0) {
      var duration = seq[0];
      print('Starting at $duration');
      CountdownTimer countdownTimer = CountdownTimer(
        Duration(seconds: duration),
        Duration(seconds: _iteration),
      );

      var sub = countdownTimer.listen(null);
      sub.onData((timer) {
        if (timer.remaining > Duration(seconds: 0)) {
          print('$duration, ${timer.remaining.inSeconds}');
        } else {
          sub.cancel();
          _countdown(seq.sublist(1));
        }
      });
    }
  }

  _countdown(_sequence);
}

除非另有说明,否则结果应如下所示,行之间的暂停时间为5秒:

Starting at 21
21, 16
21, 11
21, 6
21, 1          <-- This one should only pause 1 second before continuing
Starting at 10
10, 5
10, 0          <-- This one should immediately continue
Starting at 8
8, 3           <-- This one should only pause 3 seconds before continuing
答案

Dart / Flutter支持使用CountDownTimer进行倒计时。下面是两个示例,一个没有UI,一个在屏幕中央有一个简单的文本(超时= 10秒,步骤= 1秒,你可以改为任何你想要的)

例1:

import 'package:quiver/async.dart';

void main() {
  const timeOutInSeconds = 10;
  const stepInSeconds = 2;
  int currentNumber = 0;

  CountdownTimer countDownTimer = new CountdownTimer(
      new Duration(seconds: timeOutInSeconds),
      new Duration(seconds: stepInSeconds));

  var sub = countDownTimer.listen(null);
  sub.onData((duration) {
    currentNumber += stepInSeconds;
    int countdownNumber = timeOutInSeconds - currentNumber;
    // Make it start from the timeout value
    countdownNumber += stepInSeconds;
    print('Your message here: $countdownNumber');
  });

  sub.onDone(() {
    print("I'm done");

    sub.cancel();
  });
}

例2:

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

void main() {
  runApp(new MaterialApp(home: new CountdownTimerPage()));
}

class CountdownTimerPage extends StatefulWidget {
  @override
  CountdownTimerPageState createState() => new CountdownTimerPageState();
}

class CountdownTimerPageState extends State<CountdownTimerPage> {
  final timeOutInSeconds = 10;
  final stepInSeconds = 2;
  int currentNumber = 0;

  CountdownTimerPageState() {
    setupCountdownTimer();
  }

  setupCountdownTimer() {
    CountdownTimer countDownTimer = new CountdownTimer(
        new Duration(seconds: timeOutInSeconds),
        new Duration(seconds: stepInSeconds));

    var sub = countDownTimer.listen(null);
    sub.onData((duration) {
      currentNumber += stepInSeconds;

      this.onTimerTick(currentNumber);
      print('Your message here: $currentNumber');
    });

    sub.onDone(() {
      print("I'm done");

      sub.cancel();
    });
  }

  void onTimerTick(int currentNumber) {
    setState(() {
      currentNumber = currentNumber;
    });
  }

  @override
  Widget build(BuildContext context) {
    int number = timeOutInSeconds - currentNumber;
    // Make it start from the timeout value
    number += stepInSeconds;
    return new Scaffold(
      body: new Center(
          child: new Text(
        "Your message here: $number",
        style: new TextStyle(color: Colors.red, fontSize: 25.0),
      )),
    );
  }
}
另一答案

试试这个!

Demo

import 'dart:async';

import 'package:flutter/material.dart';

void main() => runApp(new MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'NonStopIO',
      theme: new ThemeData(
        primarySwatch: Colors.red,
      ),
      home: new MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => new _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  var _sequence = [10, 10, 8];

  @override
  void initState() {
    super.initState();
    startTimer(0);
  }

  startTimer(int index) async {
    if (index < _sequence.length) {
      print("Sequence $index - countdown :  ${_sequence[index]} ");
      new Timer.periodic(new Duration(seconds: 5), (timer) {
        if ((_sequence[index] / 5) >= timer.tick) {
          print("${_sequence[index] - timer.tick * 5}");
        } else {
          timer.cancel();
          startTimer(index + 1);
        }
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text('NonStopIO'),
      ),
      body: new Center(
        child: new Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            new Text(
              'Counter',
            ),
            new Text(
              '',
            ),
          ],
        ),
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
}
另一答案
// Start the periodic timer which prints something every 5 seconds
Timer timer = new Timer.periodic(new Duration(seconds: 5), (timer) {
  print('Something');
});

// Stop the periodic timer using another timer which runs only once after specified duration
new Timer(new Duration(minutes: 1), () {
  timer.cancel();
});
另一答案

我找到了另一个满足你的要求的答案。试试这个,

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

void main() => runApp(new MyApp());

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => new _MyAppState();
}

class _MyAppState extends State<MyApp> {

  @override
  void initState() {

    new CountdownTimer(new Duration(minutes: 1), new Duration(seconds: 5)).listen((data) {
      print('Something');
      print('Remaining time: ${data.remaining.inSeconds}');
    });
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return new Container(
    );
  }
}

以上是关于创建一个倒计时器,为列表中的每个值每5秒打印一次剩余时间的主要内容,如果未能解决你的问题,请参考以下文章

matlab 初见定时器

位置值每隔几秒更改一次 - navigator.geolocation.getCurrentPosition

java启用一个倒计时任务

如何在 GraphQL 突变/解析器中为每个用户创建和停止唯一的计时器

vue-实现倒计时功能

如何每 5 秒更改一次视图?