首页 > 解决方案 > 当 Flutter 中的全局变量更改(异步)时更新小部件

问题描述

我对 Flutter 还很陌生,我发现自己陷入了我挖的坑。

我想要完成的事情很简单。我有一个全局变量。比方说var PlayerPointsToAdd。然后我有这个有状态的小部件,它应该在每次这个全局变量不为零时更新自己。我希望能够addPointsToPlayer()从另一个小部件调用。

到目前为止,我对有状态小部件的理解到此为止setState((){}),我只能在有状态小部件本身内部调用。

下面的代码位于有状态小部件内的容器内。每当按下此按钮时,它都会根据返回的新列表调用 setState PlayerScoreBoard.add()

...
child: RaisedButton(
                        onPressed: () {
                          setState(() {
                            if (PointsToAddPlayer != 0) {
                              for (int i = 0; i < PointsToAddPlayer; i++) {
                                PlayerScoreBoard.add(new Icon(
                                    Icons.check_circle_outline,
                                    size: 11));
                              }
                              PointsToAddPlayer = 0;
                            }

我一直在阅读文档并在 YouTube 上观看 Flutter 视频,所以请不要忽略这个问题。我真的很难理解这一点。

我想我必须使用 Streams 来做到这一点。它们看起来有点复杂,但如果这是我使用它们的唯一方法。这是否意味着我应该创建一个全局变量,最好是一个包含变量的类,并将其变量流式传输到变量更新时需要更新的每个其他小部件。因此,此 ScoreBoard 小部件必须侦听来自全局类的 Stream 并自行更新。这是否允许我更改全局类中的变量并将相应的小部件自动更新为新状态?这是否意味着每个依赖于自身外部变量的小部件都必须监听流?我真的很感谢 ELI5 对 Stateful Widgets 和 Streams 之间的关系。

而且因为这个全局数据会一遍又一遍地更新很多次,所以使用 Future 是不可能的。

非常感谢。

我错误地说了一个全局类变量。我的意思是说像地图这样的东西,在那里我可以有类似的东西gameData.PlayerPoints,或gameData.turn

标签: flutterdart

解决方案


您可以尝试ValueListenableBuilder

import 'package:flutter/material.dart';

final playerPointsToAdd =
    ValueNotifier<int>(0); //TODO 1st: ValueNotifier declaration

void main() => runApp(TestApp());

class TestApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) => MaterialApp(
        routes: {
          '/': (context) => HomePage(),
        },
      );
}

//TODO you can use StatelessWidget either
class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  @override
  Widget build(BuildContext context) => Scaffold(
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              RaisedButton(
                // TODO 3rd: change the value
                onPressed: () => playerPointsToAdd.value++,
                child: Text('Increase'),
              ),
              ValueListenableBuilder(
                //TODO 2nd: listen playerPointsToAdd
                valueListenable: playerPointsToAdd,
                builder: (context, value, widget) {
                  //TODO here you can setState or whatever you need
                  return Text(
                      //TODO e.g.: create condition with playerPointsToAdd's value
                      value == 0
                          ? 'playerPointsToAdd equals 0 right now'
                          : value.toString());
                },
              ),
              RaisedButton(
                onPressed: () => playerPointsToAdd.value--,
                child: Text('Decrease'),
              ),
            ],
          ),
        ),
      );
}



推荐阅读