flutter - 如何使用计时器更新小部件

在我的应用程序中,菜单中有带有“截止”时间的项目。到达截止时间后,该项目变为红色并被禁用,并附有一条说明“已错过截止时间”的注释。

除了对于在截止时间过去后观看菜单的用户而言,显示不会动态更新之外,这工作正常。这对我当前的应用程序来说不是主要问题,如果有人想坐下来观看菜单并注意到它仅在您关闭并重新打开菜单时更新,我不在乎。

但作为一个学习练习,如果我能做到在时间过后重建菜单项,那就太好了。

然而,我不想将大型菜单树变成有状态的小部件。使用有状态小部件执行此操作非常简单,下面的最小示例(基于 flutter 默认应用程序)显示了所需的效果。有两个字段使用每秒仅调用 setState 的计时器定期(每秒)更新。

import 'dart:async';

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

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

class _MyHomePageState extends State<MyHomePage> {
  DateTime _markedTime;

  // Current Time plus a few seconds....
  void _markTheTime() {
    setState(() {
      _markedTime = DateTime.now().add(Duration(seconds: 15));
    });
  }

  // For the purpose of this test we won't use the intl package.
  String hhmmssFromDateTime(DateTime tm) {
    if (tm == null) {
      return null;
    }
    return '${zeroPadded(tm.hour)}:${zeroPadded(tm.minute)}:${zeroPadded(
        tm.second)}';
  }

  String zeroPadded(int number) => number.toString().padLeft(2, '0');

  String get markedTime => hhmmssFromDateTime(_markedTime);

  String get currentTime => hhmmssFromDateTime(DateTime.now());

  Timer rebuildTimer;

  @override
  void initState() {
    rebuildTimer = Timer.periodic(Duration(seconds: 1), (timer) {
      setState(() {

      });
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            _markedTime == null
                ? Text('Mark the time with the FAB...')
                : Text(
              'Marked Time: $markedTime',
              style: Theme
                  .of(context)
                  .textTheme
                  .bodyText1
                  .copyWith(
                  color: DateTime.now().isAfter(_markedTime)
                      ? Colors.red
                      : Colors.blue),
            ),
            Text(
              'Current Time: $currentTime',
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _markTheTime,
        tooltip: 'Set',
        child: Icon(Icons.lock_clock),
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
}

我认为解决方案在于包裹在 Column 周围的 StatefulBuilder,而不是有状态的 Widget。但是我不明白 StatefulBuilders,尽管它们看起来非常好用。

我还想知道是否有可能在 FloatingActionButton 周围再包装一个按钮,以便在标记的时间到期之前点击按钮后禁用该按钮。

我认为我最终想要实现的是一种使小部件树的各个部分相互独立地重建的方法。因此,例如使用单独的计时器,Fab 应在计时器到期时重建,而另一个周期性计时器应每秒更新“时间显示”。

最佳答案

使用 timer_builder package .一个例子:

  @override
  Widget build(BuildContext context) {
    return TimerBuilder.scheduled(
      [cutoffTime],
      builder: (context) {
        ...
      }
    );
  }

https://stackoverflow.com/questions/63564367/

相关文章:

python - Django:使用 django-storage 从 S3 创建 zipfile

Python - 在 asyncio 中取消任务?

amazon-web-services - AWS API 网关上的剥离 header

php - 带有 "sometimes"规则的 Laravel Validator 自定义消息

python - 对包含 str 和元组的 Pandas MultiIndex 进行排序

git - 以编程方式为新的 Azure 存储库设置默认分支名称

python-3.x - TypeError : on heapq. heapop on pytho

python - 通过 Python 的 gRPC API 服务器无法工作

java - 无法在 Linux 上的 Intellij 中指定 SDK

c# - 如何从 .NET Core 3.1 中的 DI 获取 SignalR IHubContex