Flutter:倒数计时器

Flutter: Countdown Timer

我正在尝试创建一个计时器应用程序,该应用程序具有针对不同任务的多个倒数计时器。我面临的问题是,如果我启动一次性计时器并按下后退按钮,计时器就会停止。所以我想要,该计时器 运行 直到它被暂停或计时器结束并提醒用户或应用程序被销毁。帮助我如何使用 Flutter 执行此操作?

任何示例代码都会受到赞赏?

enter link description here

CountDownController _controller = CountDownController();

CircularCountDownTimer(
                width: MediaQuery.of(context).size.width / 6,
                height: MediaQuery.of(context).size.width / 6,
                duration: 120,
                fillColor: Colors.green,
                ringColor: Colors.white,
                controller: _controller,
                backgroundColor: Colors.white54,
                strokeWidth: 10.0,
                strokeCap: StrokeCap.round,
                isTimerTextShown: true,
                isReverse: false,
                onComplete: () {
                  Notify();
                },
                textStyle: TextStyle(fontSize: 20.0, color: 
      Colors.black),
              ),

弹回时,小部件中的任何“状态”都将被销毁。

你可以采取三种方法来防止“状态”被破坏(或内存释放):

  • 使用静态 属性
  • Provider
  • 使用状态管理器
  • 通过静态实例使用状态管理器

还有很多方法可以管理你的状态,这里就不多说了,详见this repo

静态属性

静态 属性 类似于 class 之外的变量,例如:

// prefix "_" for private variable
const _myStaticVar = 'hello world';

class MyWidget {}

相反,它是基于 class 的变量。这意味着它可以帮助您更多地描述变量。像classDog可以有静态的属性static final footShouldHave = 4。基于 Class 的编程很受欢迎,因为它可以管理您的状态和 class“内部”的任何逻辑操作,并使其更易于理解和编码。

当 class 被销毁(内存释放)时,class 中的任何“状态”都应该从堆栈中弹出,而不是静态的。您可以通过了解编译器的工作原理来查看更多详细信息。

对于你的情况,你可以这样做:

class MyTimer extends StatlessWidget {
  static DateTime? starter;

  Widget build(context) {
    if (starter == null) {
      starter = DateTime.now();
    }
    final secondPass = (DateTime.now().millisecondsSinceEpoch - starter!.millisecondsSinceEpoch) / 1000;
    final secondLeft = 60 - secondPass;
    return Text(secondLeft.toString());
  }
}

通过Provider

提供状态管理器

Provider 是为 flutter 制作的,也由 flutter 团队维护。通过从 context.

访问它可以让您轻松管理 class

您还可以设置 class 创建的方式。

  • lazy,只在需要时创建
  • future
  • 中创建
  • ...

在你的情况下,它应该是这样的:

  1. 建立你的帮手classTimerManager
class TimerManager {
  final DateTime? starter;

  void startIfNeed() {
    if (starter != null) {
      starter = DateTime.now();
    }
  }

  num get secondLeft => 60 - (DateTime.now().millisecondsSinceEpoch - starter!.millisecondsSinceEpoch) / 1000
}
  1. 绑定Provider
class Homepage extends statelessWidget {
  Widget build(context) {
    return TextButton(
      onPressed: () => navigateToTimer(context),
      child: Text('go'),
    );
  }

  void navigateToTimer(Build context) {
    Navigator.of(context).push(
      MaterialPageRoute(builder: (_) => MyTimer()),
    );
  } 
}

void main() {
  runApp(MaterialApp(
    home: Provider<TimerManager>(
      create: () => TimerManager(),
      child: Homepage(),
    )
  ));
}
  1. 从你的 context 获取它。

现在,当您的小部件发布时,它仍然存在于父级 context 中(如果它们确实存在父级)。

// remember to import provider to able `context.read()`.
// see more detail in document.
import 'package:provider/provider.dart';

class MyTimer extends StatlessWidget {
  Widget build(context) {
    final manager = context.read<TimerManager>();
    manager.startIfNeed();

    return Text(manager.secondLeft.toString());
  }
}

静态实例

1 和 2 的一种组合方法。

class TimerManager {
  // make it singleton
  static final TimerManager  instance = TimerManager._();

  // It is now private constructor
  const TimerManager._();

  ...
}

只需在您的小部件中调用它

class MyTimer extends StatlessWidget {
  Widget build(context) {
    TimerManager.instance.startIfNeed();

    return Text(TimerManager.instance.secondLeft.toString());
  }
}

总结

一般情况下没有最好的方法来保持你的状态,但在你的情况下,我推荐Provider方法。