9

I am fairly new to Flutter and I find myself in a hole I have dug.

What I want to accomplish is quite simple. I have a global variable. Let's say var PlayerPointsToAdd. Then I have this Stateful Widget that should update itself everytime this global variable is not zero. I want to be able to call the addPointsToPlayer() from another widget.

So far my understanding of the Stateful widgets end at the setState((){}) which I can only call inside the Stateful widget itself.

The code below is inside a container inside a Stateful widget. Whenever this button is pressed, it calls the setState according to the new list that PlayerScoreBoard.add() returns.

...
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;
                            }

I have been reading the documentation and watching the Flutter videos on YouTube so please do not dismiss the question. I am genuinely having trouble understanding this.

I figure I have to use Streams to do this. They seem a bit complicated, but if that's the only way I will use them. Does this mean that I should create a global variable, preferably a class with variables in it and make it stream it's variables to every other widget that needs to update when the variables update. So therefore this ScoreBoard widget must listen to the Stream coming from the global class and update itself. Will this allow me to change the variables in a global class and update the respective widgets to their new states automatically? And does this mean that every widget that relies on variables outside itself must be listening to streams? I would really appreciate an ELI5 to the relationship between Stateful Widgets and Streams.

And because this global data will be updated many times over and over again, using a Future is not possible.

Thank you very much.

I mistakenly said a global class variable. I meant to say something like a Map, where I can have something like gameData.PlayerPoints, or gameData.turn.

1 Answer 1

30

You can try 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'),
              ),
            ],
          ),
        ),
      );
}


Sign up to request clarification or add additional context in comments.

7 Comments

Wow. I had no idea this existed. I wish there were more tutorials on things like these rather than streams and futures. I get that Streams are very important, but this was super simple to implement and it was exactly what I needed. The only thing I couldn't figure out is how to have the ValueListenableBuilder listen to a Map, rather than an int. But creating separate variables is so far working just fine. Thank you very very much!
If you want to listen to a Map, change ValueNotifier declaration to ValueNotifier<Map<String, dynamic>> and notify listeners after value changes playerPointsToAdd.notifyListeners();. This is not the best solution, because method notifyListeners is protected and sometimes has surprising behavior, but it works and is commonly used. FYI: in the future you can use BLoC instead of streams - coding is much simpler then:)
I'm trying to use ValueNotifier<List> as describe between different dart files but it's not rendering my builder. I'm updating a global project variable from page1, the variable is placed on page2, and my ValueNotifier is placed on page3. Someone knows why my builder is not rendering? (just to insure that everything works as expected, when I render my page manually the value is update).
@genericUser, post your own question with a minimal, reproducible example. It's way easier to us to help then :)
Thanks @Owczar but I have already implemented things differently ;)
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.