我正在try 使用ProviderStateless小部件页面来更新倒计时UI.

当我运行以下所有操作时,我会在秒表每1秒的滴答声中在控制台中收到两条打印消息:

例如

flutter: build()
flutter: _buildCountDown()

此外,remaining值实际上不会在UI中更新.

But if I:

  • 将页面设为StatefulWidget
  • replace the variable access with Consumer<CountdownProvider> syntax 例如
return Consumer<CountdownProvider>(
  builder: (_, countdownProvider, __) {
    return Text(countdownProvider.remaining.toString()),
});

...一切都按预期进行:UI正确更新,我没有得到build()的打印输出,只有_buildCountDown(),这正是我想要的.

Q) What am I doing wrong that means I can't make this a Stateless widget that updates as expected?


  1. 主要的dart我有这样的提供者:
return MultiProvider(
  providers: [        
    ChangeNotifierProvider(
      create: (_) => CountdownProvider(),
    ),
  ],
)
  1. 我编写了一个简单的倒计时提供者-CountdownProvider:
class CountdownProvider extends ChangeNotifier {

  int remaining = 0;
  final Stopwatch _stopwatch = Stopwatch();
  late Timer _timer;

  void start(int val) {
    remaining = val;
    _timer = Timer.periodic(const Duration(seconds: 1), _onTick);
    _stopwatch.start();
  }

  void _onTick(Timer timer) {
    remaining--;
    if (remaining < 0) {
      return;
    }
    notifyListeners();
  }

  void stop(bool skipNotify) {
    _timer.cancel();
    _stopwatch.stop();

    if (skipNotify) {
      _stopwatch.reset();
      remaining = 0;
      return;
    }
    notifyListeners();
  }
}
  1. 显示页面:PageCountdown:
class PageCountdown extends StatelessWidget {
  const PageCountdown({
    Key? key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    // 10 seconds default countdown
    Provider.of<CountdownProvider>(context, listen: false).start(10);

    print("build()");
    return Scaffold(
      body: _buildContent(context),
    );
  }

  Widget _buildContent(BuildContext context) {
    return SafeArea(
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.center,
        children: [
          _buildCountDown(context),
        ],
      ),
    );
  }

  Widget _buildCountDown(BuildContext context) {
    int remaining = Provider.of<CountdownProvider>(context).remaining;

    print("_buildCountDown()");

    return Text(
      remaining.toString(),
    );
  }
}

推荐答案

PageCountdown是单个小部件,当计数器滴答作响时会重新生成.build开头的start(10)将在每次重建时将remaining重置为10.像这样的方法会奏效:

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

  @override
  Widget build(BuildContext context) {
    // 10 seconds default countdown
    Provider.of<CountdownProvider>(context, listen: false).start(10);

    print("build()");
    return const Scaffold(
      body: Countdown(),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.center,
        children: [
          _buildCountDown(context),
        ],
      ),
    );
  }

  Widget _buildCountDown(BuildContext context) {
    int remaining = Provider.of<CountdownProvider>(context).remaining;

    print("_buildCountDown()");

    return Text(
      remaining.toString(),
    );
  }
}

Flutter相关问答推荐

Fighter:基于ChangeNotifier状态动态更新AppBar中的图标

为什么我的PIN字段在第一次打字时不显示数字?

Firebase WHERE过滤器在日期字段中不起作用

如何使DropDownMenu宽度等于TextFormfield?

为什么用户界面不会在Flight中的复选框中更改?

Flutter守护进程无法启动

抖动问题:检测到0个或2个或更多具有相同值的[DropdownMenuItem]

dart /长笛中的返回早期模式和拆分方法

如何在 VS Code 中启用 Flutter 运行/调试工具栏?

Flutter:注册 UI 出现 UI 问题(将注册框提升到顶部并向电话号码 pin 码添加一个框)

以编程方式在 flutter 中安装 apk 时解析错误

使用Flutter项目设置Firebase遇到困难?这些解决方案或许能帮到你!

输入处于活动状态时如何设置文本字段标签的样式?

如何在 Flutter 中滚动时为多个小部件设置动画

通过点击缩略图加载全屏图像

Flutter snapShot.hasData 为假但响应有数据

Getx Flutter 在更新值时抛出空错误

http响应在Flutter 中返回307

在 Flutter 应用程序中全局使用 assets 文件夹

Flutter - 如何调用此函数?