0

I am having two stateful classes - FirstClass and SecondClass. In FirstClass I have two buttons; '+' and '-', which will receive random numbers (such as 1+3 or 5-2). Those random numbers are then to be displayed as text in SecondClass.

You can find a few examples on internet on how to pass data to a stateful widget (here are some good links).

Passing Data to a Stateful Widget

Passing data to StatefulWidget and accessing it in it's state in Flutter

https://medium.com/@maksimrv/reactive-app-state-in-flutter-73f829bcf6a7 The best way to passing data between widgets in Flutter

What all these examples have in common is that they assume that your data is final. Since my numbers are random I cannot use final- and this is where I get stuck...

I was a bit unclear in my first question, but the goal is to get an output like 2 + 5 =_ . And the user will fill in the answer in a textfield. The answer will then, after a button-press, pass back to the sum and see if the answer is correct. If answer is correct -> do this, else -> do that.

Added a nicer keyboard.

import 'package:flutter/material.dart';
import 'dart:math';

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

class MyHome extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'passing data',
      theme: ThemeData(primarySwatch: Colors.red),
      home: FirstClass(),
    );
  }
}

class FirstClass extends StatefulWidget {
  @override
  _FirstClassState createState() => _FirstClassState();
}

class _FirstClassState extends State<FirstClass> {
  final random = Random();
  int a, b, sum;
  String output;

  void changeData(String buttonName) {
    setState(() {
      a = random.nextInt(10);
      b = random.nextInt(10);

      if (buttonName == '+') {
        sum = a + b;
        output = '$a + $b = ';
      } else if (buttonName == '-') {
        if (a >= b) {
          sum = a - b;
          output = '$a - $b = ';
        } else if (b > a) {
          //sum cannot be negative here
          sum = b - a;
          output = '$b - $a = ';
        }
      }
      print(sum.toString());
      Navigator.of(context).popUntil(ModalRoute.withName('/'));
      Navigator.of(context).push(MaterialPageRoute(
          builder: (context) => SecondClass(
                sum: sum,
                refresh: changeData,
                output: output,
                  )));
        });
      }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('First Screen'),
      ),
      body: Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: <Widget>[
            //      Text('$a + $b = $sum'),
            RaisedButton(child: Text('+'), onPressed: () => 
changeData('+')),
            RaisedButton(child: Text('-'), onPressed: () => changeData('- 
   ')),
               ],
            ),
          ),
        );
      }
    }

class SecondClass extends StatefulWidget {
  final int sum;
  final String output;
  final String correction;

  final Function refresh;

  SecondClass({this.sum, this.refresh, this.output, this.correction});

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

class _SecondClassState extends State<SecondClass> {
  String enterAnswer;
  String correct;

  void changeAnswer() {
    if (enterAnswer.isNotEmpty) {
      if (enterAnswer == widget.sum.toString()) {
        correct = 'Correct';
        print('Correct Answer.');
      } else {
         correct = 'Wrong Answer';
         print('Wrong Answer');
      }
    } else {
      correct = 'Enter Value First';
      print('Enter Value First');
    }
  }

  @override
  void initState() {
    super.initState();
  }

  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Second Screen'),
      ),
      body: Center(
        child: Container(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              Row(
                mainAxisAlignment: MainAxisAlignment.center,
                 children: <Widget>[
                  Text(widget.output),
                  Container(
                      width: 50.0,
                      TextField(
                        keyboardType: TextInputType.number,
                        onChanged: (val) {
                          enterAnswer = val;
                         },
                      )),
                ],
              ),
              RaisedButton(
                  child: Text('Check Answer'), onPressed: () => 
changeAnswer()),
              Text('$correct'),
            ],
          ),
        ),
      ),
    );
  }
}

How come the '$correct' won't display as a text? I tried to do the same in another project and it worked, so what am I doing wrong here?

Cœur
  • 37,241
  • 25
  • 195
  • 267
J.W
  • 1,135
  • 4
  • 13
  • 21

2 Answers2

2

What you need is callback function to get the random value again.

I assume you want to show the random sum value in second screen() Separate Class.

This is with Navigator & Class Constructors.

code:

import 'package:flutter/material.dart';
import 'dart:math';

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

class MyHome extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'passing data',
      theme: ThemeData(primarySwatch: Colors.red),
      home: FirstClass(),
    );
  }
}

class FirstClass extends StatefulWidget {
  @override
  _FirstClassState createState() => _FirstClassState();
}

class _FirstClassState extends State<FirstClass> {
  final random = Random();
  int a, b, sum;
  String output;

  void changeData(String buttonName) {
    setState(() {
      a = random.nextInt(10);
      b = random.nextInt(10);

      if (buttonName == '+') {
        sum = a + b;
        output = '$a + $b = ';
      } else if (buttonName == '-') {
        if (a >= b) {
          sum = a - b;
          output = '$a - $b = ';
        } else if (b > a) {
          //sum cannot be negative here
          sum = b - a;
          output = '$b - $a = ';
        }
      }
      print(sum.toString());
      Navigator.of(context).popUntil(ModalRoute.withName('/'));
      Navigator.of(context).push(MaterialPageRoute(
          builder: (context) => SecondClass(
                sum: sum,
                refresh: changeData,
                output: output,
              )));
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('First Screen'),
      ),
      body: Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: <Widget>[
            //      Text('$a + $b = $sum'),
            RaisedButton(child: Text('+'), onPressed: () => changeData('+')),
            RaisedButton(child: Text('-'), onPressed: () => changeData('-')),
          ],
        ),
      ),
    );
  }
}

class SecondClass extends StatefulWidget {
  final int sum;
  final String output;

  final Function refresh;

  SecondClass({this.sum, this.refresh, this.output});

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

class _SecondClassState extends State<SecondClass> {
  String enterAnswer;

  @override
  void initState() {
    super.initState();
  }

  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Second Screen'),
      ),
      body: Center(
        child: Container(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              Row(
                mainAxisAlignment: MainAxisAlignment.center,
                children: <Widget>[
                  Text(widget.output),
                  Container(
                      width: 50.0,
                      child: TextField(
                        onChanged: (val) {
                          enterAnswer = val;
                        },
                      )),
                ],
              ),
              RaisedButton(
                onPressed: () {
                  if (enterAnswer.isNotEmpty) {
                    if (enterAnswer == widget.sum.toString()) {
                      print('Correct Answer.');
                    } else {
                      print('Wrong Answer');
                    }
                  } else {
                    print('Enter Value First');
                  }
                },
                child: Text('Check Answer'),
              )
            ],
          ),
        ),
      ),
    );
  }
}
anmol.majhail
  • 48,256
  • 14
  • 136
  • 105
0

You can pass data to second class via constructor of second class and access it by using widget.your_data. Final should be used

Because StatefulWidget inherits Widget, which is marked as @immutable, any subclass of StatefulWidget must also be immutable (i.e. all fields final).

I created simple use case by your question, see if it is what you want:

    class FirstClass extends StatefulWidget {
      @override
      FirstClassState createState() => FirstClassState();
    }

    class FirstClassState extends State<FirstClass> {
      final random = Random();
      int a, b, sum;

      void changeData() {
        setState(() {
          a = random.nextInt(10);
          b = random.nextInt(10);
          sum = a + b;
        });
      }

      @override
      Widget build(BuildContext context) {
        return Scaffold(
          body: SecondClass(
            a: a,
            b: b,
            sum: sum,
          ),
          floatingActionButton: FloatingActionButton(
            child: Icon(Icons.refresh),
            onPressed: changeData,
          ),
        );
      }
    }

and second class getting data is :

     class SecondClass extends StatefulWidget {
      final int a;
      final int b;
      final int sum;

      SecondClass({this.a, this.b, this.sum});

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

    class _SecondClassState extends State<SecondClass> {
      @override
      Widget build(BuildContext context) {
        return Container(
          child: Center(
            child: Text('${widget.a} + ${widget.b} = ${widget.sum}'),
          ),
        );
      }
    }

Here if a, b and sum value is changed in first class via setState() method, all widget using those will be recreated. Thus, second class is refreshed with new data.

Xuzan
  • 335
  • 1
  • 11
  • I do get the Integer sum to sreen 2, but I still can't get my String "output" (wich would be '$a + $b = ') to appear on the 2nd screen. – J.W Feb 14 '19 at 18:08