-2

I need to pass the value of two variables from one screen to another screen class. I can't do it.

Here is the whole code:

import 'package:flutter/material.dart';
import 'package:csv/csv.dart';
import 'package:flutter/services.dart' show rootBundle;
import 'dart:io';


//My classes
import './my classes.dart';

void main() => runApp(const MyApp());

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

  static const String _title = 'Example';

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: _title,
        home: Container(
            child: Scaffold(
        appBar: AppBar(title: const Text(_title)),
        // body: const MyStatelessWidget(),
              body: const MainWidget(),
      ),
    )
    );
  }
}

// class MyStatelessWidget extends StatelessWidget {
//   const MyStatelessWidget({Key? key}) : super(key: key);
class MainWidget extends StatefulWidget {
  const MainWidget({Key? key}) : super(key: key);

  @override
  State<MainWidget> createState() => _MainWidgetState();
}


class _MainWidgetState extends State<MainWidget> {
  CheckUserConnection _checkUserConnection = CheckUserConnection();
  InternetDialogHandler _internetDialogHandler = InternetDialogHandler();
  bool? _internetAvailable;

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


  void checkNet() async{
    _internetAvailable = await
    _checkUserConnection.checkInternetAvailability();
    setState((){});
  }



  @override
  Widget build(BuildContext context) {
    return Center(
      child: Column(
        mainAxisSize: MainAxisSize.max,
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
        children: <Widget>[
          Column(
            children: [
              GradientButton(label: 'New Game', onTap: () {
                Navigator.push(
                  context,
                  MaterialPageRoute(builder: (context) => const NewGameRoute(
                      listCount: 0, assetPath: "images/01.jpg" ///What I want to pass


                  )),
                );
              }),
              // GradientButton(label: 'Continue Game', onTap: () {
              //   return _internetAvailable == true ?
              //   {Navigator.push(
              //         context,
              //         MaterialPageRoute(builder: (context) => const NewGameRoute()),
              //       )}
              //   :
              //   _internetDialogHandler.showInternetDialog(context);
              // }),
            ],
          ),
          Column(
            children: [
              GradientButton(label: 'Back Button', onTap: () {
                Navigator.push(
                  context,
                  MaterialPageRoute(builder: (context) => const BackRoute()),
                );



                // print('Button 1');



              }),
              GradientButton(label: 'Button 2', onTap: () {print('Button 2');}),
              GradientButton(label: 'Internet', onTap: () {
                Navigator.push(
                  context,
                  MaterialPageRoute(builder: (context) => const InternetRoute()),
                );
              }),
            ],
          )
        ],
      ),
    );
  }
}


//Class for a gradient button
class GradientButton extends StatelessWidget {
  const GradientButton({Key? key, required this.label, required this.onTap}) : super(key: key);
  final String label;
  final Function onTap;

  @override
  Widget build(BuildContext context) {
    return Container(
      margin: const EdgeInsets.symmetric(vertical: 15),
      child: GestureDetector(
        onTap: () => onTap(),
        child: Container(
          padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 8),
          decoration: const BoxDecoration(
            borderRadius: BorderRadius.all(Radius.circular(4)),
            gradient: LinearGradient(
              colors: <Color>[
                Color(0xFF0D47A1),
                Color(0xFF1976D2),
                Color(0xFF42A5F5),
              ],
            ),
          ),
          child: Text(label, style: const TextStyle(fontSize: 20, color: Colors.white, fontWeight: FontWeight.normal, decoration: TextDecoration.none),),
        ),
      ),
    );
  }
}


// New Game route
var globalContext; // Declare global variable to store context from StatelessWidget

// class NewGameRoute extends StatelessWidget {
//   const NewGameRoute({key});  //original



  class NewGameRoute extends StatelessWidget {
    const NewGameRoute({
      Key? key,
      required int listCount,
      required this.assetPath,
    })  : _listCount = listCount,
          super(key: key);

    final int _listCount;

    final String assetPath;



  @override
  Widget build(BuildContext context) {
    globalContext = context; // globalContext receives context from StatelessWidget.
    return const MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'New Game',
      home: ListFromCSV(),
    );
  }
}

class ListFromCSV extends StatefulWidget {
  const ListFromCSV({Key? key}) : super(key: key);

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

class _ListFromCSVState extends State<ListFromCSV> {
  List<List<dynamic>> _listData = [
    [""]
  ];
  // int _listCount = 0;
  bool _isFirstLoad = true;
  // String assetPath = "files/main.jpg";

  @override
  void initState() {
    _loadCSV();
  }

  // This function is only triggered at init, so we only load csv once
  void _loadCSV() async {
    String rawData = await rootBundle.loadString("files/Text.csv");
    _listData = const CsvToListConverter().convert(rawData);
    // assetPath = _listData[_listCount][1] == ""
    //     ? "files/main.jpg"
    //     : _listData[_listCount][1];
  }
///


  // This function is triggered when my button is pressed
  void _nextCSV() {
    setState(() {
      _listData = _listData;
      _listCount < _listData.length - 1
          ? _isFirstLoad
          ? _isFirstLoad = false
          : _listCount++
          : _listCount;
      // assetPath =
      // _listData[_listCount][1] == "" ? assetPath : _listData[_listCount][1];
      _listData[_listCount][1] == "" ? null : _showAlertDialog();
    });
  }

  // This function makes buttons visible/invisible
  bool isVisible = true; //will be visible for the first frame

  void _isVisible() {
    setState(() {
      isVisible = !isVisible;
    });
  }


//Alert Dialog about questions and answers
  Widget _answer1TextButton(){
    return TextButton(
      child: Text(_listData[_listCount][3]),
      onPressed:  () {
        setState(() {
        assetPath = _listData[_listCount][6];
        _listCount = _listData[_listCount][2]-1;
        // _listData[_listCount][0];
        // _nextCSV();
        print('Answer 1');
        print(_listCount);
        Navigator.of(globalContext).pop();  // Popping globalContext
          });
      },
    );
  }
  Widget _answer2TextButton(){
    return TextButton(
      child: Text(_listData[_listCount][5]),
      onPressed:  () {
        setState(() {
        assetPath = _listData[_listCount][7];
        _listCount = _listData[_listCount][4]-1;
        print('Answer 2');
        print(_listCount);
        Navigator.of(globalContext).pop();  // Popping globalContext
        });
        },
    );
  }

  void _showAlertDialog() {

// set up the AlertDialog
    AlertDialog alert = AlertDialog(
      // title: Text(),
      content: Text(_listData[_listCount][1]),
      actions: [
        _answer1TextButton(),
        _answer2TextButton(),
      ],
    );

// show the dialog
    showDialog(
      barrierDismissible: false,  //use to dismiss any tap on the background of the dialog
      context: context,
      // useRootNavigator: false, //this property needs to be added
      builder: (BuildContext context) {
        return WillPopScope(
          onWillPop: () async {
            return true;   // false to disable the back button
          },
          child: alert,
        );
      },
    );
  }



  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: const Text('New Game'),
        ),
        body: Container(
          height: MediaQuery.of(context).size.height,
          decoration: BoxDecoration(
              image: DecorationImage(
                  image: AssetImage(assetPath),
                  fit: BoxFit.cover)),
          child: Column(
            mainAxisSize: MainAxisSize.min,
            children: <Widget>[
              Visibility(
                child: Column(
                  children: [
                    ClipRRect(
                      borderRadius: BorderRadius.circular(4),
                      child: Stack(
                        children: <Widget>[
                          Positioned.fill(
                            child: Container(
                              decoration: BoxDecoration(
                                  image: DecorationImage(
                                      image: AssetImage('files/sheet.jpg'),
                                      fit: BoxFit.cover)),
                            ),
                          ),
                          Text(_listData[_listCount][0]),
                        ],
                      ),
                    ),
                    Row(
                      mainAxisAlignment: MainAxisAlignment.spaceAround,
                      children: [
                        ImageButton(label: 'OK', onButtonTap: _nextCSV),
                        ImageButton(label: 'Hide', onButtonTap: _isVisible),
                        ImageButton(label: 'Test1', onButtonTap: _showAlertDialog),
                      ],
                    ),
                  ],
                ),
                visible: isVisible,
              ),
              // your other widgets
              Visibility(
                child: ImageButton(label: 'Show', onButtonTap: _isVisible),
                visible: !isVisible,
              )

            ],
          ),
        ),
      );
  }
}


//Class for a cool button
class ImageButton extends StatelessWidget {
  const ImageButton({Key? key, required this.label, required this.onButtonTap})
      : super(key: key);
  final String label;
  final Function onButtonTap;

  @override
  Widget build(BuildContext context) {
    return InkWell(
      onTap: () => onButtonTap(),
      child: Container(
        // customize you button shape and size and design
        margin: const EdgeInsets.all(8),
        padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 32),
        decoration: const BoxDecoration(
            borderRadius: BorderRadius.all(Radius.circular(2)),
            image: DecorationImage(
                image: AssetImage("files/sheet.jpg"), // you can also pass the image dynamically with variable created for the widget.
                fit: BoxFit.cover)),
        child: Center(
          child: Text(
            label,
            style: const TextStyle(
                color: Colors
                    .black, // you can get dominant colour on image and change the text color accordingly or apply shadows to the text
                fontWeight: FontWeight.w500,
                fontSize: 16),
          ),
        ),
      ),
    );
  }
}

This is how I pass data from the main screen:

GradientButton(label: 'New Game', onTap: () {
                Navigator.push(
                  context,
                  MaterialPageRoute(builder: (context) => const NewGameRoute(
                      listCount: 0, assetPath: "images/01.jpg" ///What I want to pass


                  )),
                );
              }),

This is how I get the data in another screen:

class NewGameRoute extends StatelessWidget {
    const NewGameRoute({
      Key? key,
      required int listCount,
      required this.assetPath,
    })  : _listCount = listCount,
          super(key: key);

    final int _listCount;

    final String assetPath;
...

But when I try to run my file I get the following errors:

Performing hot reload...
Syncing files to device sdk gphone64 x86 64...
lib/main.dart:223:7: Error: The getter '_listCount' isn't defined for the class '_ListFromCSVState'.
 - '_ListFromCSVState' is from 'package:example/main.dart' ('lib/main.dart').
Try correcting the name to the name of an existing getter, or defining a getter or field named '_listCount'.
      _listCount < _listData.length - 1
      ^^^^^^^^^^
lib/main.dart:226:13: Error: The getter '_listCount' isn't defined for the class '_ListFromCSVState'.
 - '_ListFromCSVState' is from 'package:example/main.dart' ('lib/main.dart').
Try correcting the name to the name of an existing getter, or defining a getter or field named '_listCount'.
          : _listCount++
            ^^^^^^^^^^
lib/main.dart:226:13: Error: The setter '_listCount' isn't defined for the class '_ListFromCSVState'.
 - '_ListFromCSVState' is from 'package:example/main.dart' ('lib/main.dart').
Try correcting the name to the name of an existing setter, or defining a setter or field named '_listCount'.
          : _listCount++
            ^^^^^^^^^^
lib/main.dart:227:13: Error: The getter '_listCount' isn't defined for the class '_ListFromCSVState'.
 - '_ListFromCSVState' is from 'package:example/main.dart' ('lib/main.dart').
Try correcting the name to the name of an existing getter, or defining a getter or field named '_listCount'.
          : _listCount;
            ^^^^^^^^^^
lib/main.dart:230:17: Error: The getter '_listCount' isn't defined for the class '_ListFromCSVState'.
 - '_ListFromCSVState' is from 'package:example/main.dart' ('lib/main.dart').
Try correcting the name to the name of an existing getter, or defining a getter or field named '_listCount'.
      _listData[_listCount][1] == "" ? null : _showAlertDialog();
                ^^^^^^^^^^
lib/main.dart:247:29: Error: The getter '_listCount' isn't defined for the class '_ListFromCSVState'.
 - '_ListFromCSVState' is from 'package:example/main.dart' ('lib/main.dart').
Try correcting the name to the name of an existing getter, or defining a getter or field named '_listCount'.
      child: Text(_listData[_listCount][3]),
                            ^^^^^^^^^^
lib/main.dart:250:31: Error: The getter '_listCount' isn't defined for the class '_ListFromCSVState'.
 - '_ListFromCSVState' is from 'package:example/main.dart' ('lib/main.dart').
Try correcting the name to the name of an existing getter, or defining a getter or field named '_listCount'.
        assetPath = _listData[_listCount][6];
                              ^^^^^^^^^^
lib/main.dart:250:9: Error: The setter 'assetPath' isn't defined for the class '_ListFromCSVState'.
 - '_ListFromCSVState' is from 'package:example/main.dart' ('lib/main.dart').
Try correcting the name to the name of an existing setter, or defining a setter or field named 'assetPath'.
        assetPath = _listData[_listCount][6];
        ^^^^^^^^^
lib/main.dart:251:32: Error: The getter '_listCount' isn't defined for the class '_ListFromCSVState'.
 - '_ListFromCSVState' is from 'package:example/main.dart' ('lib/main.dart').
Try correcting the name to the name of an existing getter, or defining a getter or field named '_listCount'.
        _listCount = _listData[_listCount][2]-1;
                               ^^^^^^^^^^
lib/main.dart:251:9: Error: The setter '_listCount' isn't defined for the class '_ListFromCSVState'.
 - '_ListFromCSVState' is from 'package:example/main.dart' ('lib/main.dart').
Try correcting the name to the name of an existing setter, or defining a setter or field named '_listCount'.
        _listCount = _listData[_listCount][2]-1;
        ^^^^^^^^^^
lib/main.dart:255:15: Error: The getter '_listCount' isn't defined for the class '_ListFromCSVState'.
 - '_ListFromCSVState' is from 'package:example/main.dart' ('lib/main.dart').
Try correcting the name to the name of an existing getter, or defining a getter or field named '_listCount'.
        print(_listCount);
              ^^^^^^^^^^
lib/main.dart:263:29: Error: The getter '_listCount' isn't defined for the class '_ListFromCSVState'.
 - '_ListFromCSVState' is from 'package:example/main.dart' ('lib/main.dart').
Try correcting the name to the name of an existing getter, or defining a getter or field named '_listCount'.
      child: Text(_listData[_listCount][5]),
                            ^^^^^^^^^^
lib/main.dart:266:31: Error: The getter '_listCount' isn't defined for the class '_ListFromCSVState'.
 - '_ListFromCSVState' is from 'package:example/main.dart' ('lib/main.dart').
Try correcting the name to the name of an existing getter, or defining a getter or field named '_listCount'.
        assetPath = _listData[_listCount][7];
                              ^^^^^^^^^^
lib/main.dart:266:9: Error: The setter 'assetPath' isn't defined for the class '_ListFromCSVState'.
 - '_ListFromCSVState' is from 'package:example/main.dart' ('lib/main.dart').
Try correcting the name to the name of an existing setter, or defining a setter or field named 'assetPath'.
        assetPath = _listData[_listCount][7];
        ^^^^^^^^^
lib/main.dart:267:32: Error: The getter '_listCount' isn't defined for the class '_ListFromCSVState'.
 - '_ListFromCSVState' is from 'package:example/main.dart' ('lib/main.dart').
Try correcting the name to the name of an existing getter, or defining a getter or field named '_listCount'.
        _listCount = _listData[_listCount][4]-1;
                               ^^^^^^^^^^
lib/main.dart:267:9: Error: The setter '_listCount' isn't defined for the class '_ListFromCSVState'.
 - '_ListFromCSVState' is from 'package:example/main.dart' ('lib/main.dart').
Try correcting the name to the name of an existing setter, or defining a setter or field named '_listCount'.
        _listCount = _listData[_listCount][4]-1;
        ^^^^^^^^^^
lib/main.dart:269:15: Error: The getter '_listCount' isn't defined for the class '_ListFromCSVState'.
 - '_ListFromCSVState' is from 'package:example/main.dart' ('lib/main.dart').
Try correcting the name to the name of an existing getter, or defining a getter or field named '_listCount'.
        print(_listCount);
              ^^^^^^^^^^
lib/main.dart:281:31: Error: The getter '_listCount' isn't defined for the class '_ListFromCSVState'.
 - '_ListFromCSVState' is from 'package:example/main.dart' ('lib/main.dart').
Try correcting the name to the name of an existing getter, or defining a getter or field named '_listCount'.
      content: Text(_listData[_listCount][1]),
                              ^^^^^^^^^^
lib/main.dart:316:37: Error: The getter 'assetPath' isn't defined for the class '_ListFromCSVState'.
 - '_ListFromCSVState' is from 'package:example/main.dart' ('lib/main.dart').
Try correcting the name to the name of an existing getter, or defining a getter or field named 'assetPath'.
                  image: AssetImage(assetPath),
                                    ^^^^^^^^^
lib/main.dart:336:42: Error: The getter '_listCount' isn't defined for the class '_ListFromCSVState'.
 - '_ListFromCSVState' is from 'package:example/main.dart' ('lib/main.dart').
Try correcting the name to the name of an existing getter, or defining a getter or field named '_listCount'.
                          Text(_listData[_listCount][0]),
                                         ^^^^^^^^^^

How do I pass data to class '_ListFromCSVState'? Note that in the original version of the code, I define these variables in this class. And everything works. But I need the value of this data to be taken from the main screen.

Thanks in advance.

Edit 1. Now I have only one error:

The named parameter 'listCount' is required, but there's no corresponding argument.

It leads to this part of the code:

@override
  Widget build(BuildContext context) { // removed materialApp from here
    return ListFromCSV();
  }
}

ListFromCSV() is underlined in red.

Edit 2. On Yeasin Sheikh's advice, I modified this part of the code like this:

@override
  Widget build(BuildContext context) { // removed materialApp from here
    return ListFromCSV(listCount: _listCount, assetPath: assetPath);
  }

Now everything works. I want to do the same with Prabhakaran's version of the code to make sure that I understand everything correctly.

Texter
  • 95
  • 10
  • You should use the Provider package to pass the required data. – Milie Jul 11 '22 at 16:18
  • Oh, thanks. I didn't expect it to be so difficult. I was hoping for some standard out of the box solution. – Texter Jul 11 '22 at 16:42
  • The Provider package is quite simple to use. – Milie Jul 11 '22 at 16:44
  • Thanks again. I am sure that when I install it, I will have many questions, haha. Naturally, I will make many attempts and ask a new question after that. – Texter Jul 11 '22 at 16:47
  • https://docs.flutter.dev/development/data-and-backend/state-mgmt/simple start here and go from there. Best of luck. – Milie Jul 11 '22 at 16:48
  • Have you tried passing your data via the arguments parameter in MaterialPageRoute ? – Vipin Kumar Kashyap Jul 11 '22 at 18:25
  • Yes. I pass data from one screen to another in this way. The problem is that I can't pass data inside the second screen. – Texter Jul 12 '22 at 11:59

2 Answers2

2

You don't need to use multiple MaterialApp, Just use MaterialApp once on root widget.

class NewGameRoute extends StatelessWidget {
  const NewGameRoute({
    Key? key,
    required int listCount,
    required this.assetPath,
  })  : _listCount = listCount,
        super(key: key);

  final int _listCount;

  final String assetPath;

  @override
  Widget build(BuildContext context) { // removed materialApp from here
    return ListFromCSV();
  }
}

To get variable on state class from StatefulWidget

class ListFromCSV extends StatefulWidget {
  final int listCount;
  const ListFromCSV({
    Key? key,
    required this.listCount,
  }) : super(key: key);

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

class _ListFromCSVState extends State<ListFromCSV> {
  List<List<dynamic>> _listData = [
    [""]
  ];
  late int _listCount = widget.listCount;

Also avoid using global context. You can also check riverpod or flutter_bloc for state management.

You can check more about passing data

More about MaterialApp

Md. Yeasin Sheikh
  • 54,221
  • 7
  • 29
  • 56
  • Thanks for these fixes. I will read your links. But at the moment I still get Error: The getter '_listCount' isn't defined for the class '_ListFromCSVState'. – Texter Jul 11 '22 at 16:35
  • On top state level(class `_ListFromCSVState`), `_listCount` is commented out. – Md. Yeasin Sheikh Jul 11 '22 at 16:46
  • I know. I commented out this line on purpose, because I want this value to be taken from another place. – Texter Jul 11 '22 at 16:48
  • You can get using constructor on `ListFromCSV` and use `widget._listCount` – Md. Yeasin Sheikh Jul 11 '22 at 16:51
  • Thank you. To be honest, I don't really understand what you're talking about. Today I just learned how to transfer data from one screen to another. Or rather, I thought so, haha. And now I understand that it is not so. – Texter Jul 11 '22 at 16:55
  • I've included the example. Also You need to maintain the data flow from parent widget to its children, You can check [cookbook](https://docs.flutter.dev/cookbook) for startup – Md. Yeasin Sheikh Jul 11 '22 at 17:04
  • Thank you. Now I have only one error, which I have indicated in Edit 1. – Texter Jul 12 '22 at 11:58
  • You need to pass data like `ListFromCSV(listCount:2);`, You can check more about [using-constructors](https://dart.dev/guides/language/language-tour#using-constructors) – Md. Yeasin Sheikh Jul 12 '22 at 12:03
  • Yes, everything is working now. I modified that part of the code. Thanks for your patience, help and links. – Texter Jul 12 '22 at 12:25
1
  1. You should not use two material apps for an application. Use only one at the root level

  2. The use of the NewGameRoute widget is not necessary as it simply calls another widget without any business logic. So you can remove that and from MainWidget you can navigate to the ListFromCSV page like this.

    GradientButton(label: 'New Game', onTap: () {
    Navigator.push(context, MaterialPageRoute(builder: (context) => ListFromCSV(listCount: 0, assetPath: "images/01.jpg")) ); }),

Note: If you don't want the route to get stacked (prevent back) use Navigator.pushReplacement instead of Navigator.push

Now modify your ListFromCSV widget to accept the params.

class ListFromCSV extends StatefulWidget {
  const ListFromCSV({Key? key, required this.listCount, required assetPath}) : super(key: key);
  final int listCount;
  final String assetPath; 

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

And access it like this,

class _ListFromCSVState extends State<ListFromCSV> {
  List<List<dynamic>> _listData = [
    [""]
  ];
  int _listCount = 0;
  bool _isFirstLoad = true;
  String assetPath = "";
  
  @override
  void initState() {
    super.initState();
    assetPath = widget.assetPath;
    _listCount = widget.listCount;
    _loadCSV();
  }
}
Prabhakaran
  • 1,524
  • 2
  • 13
  • 21
  • Hello! 1. Yes, Yeasin Sheikh pointed this out to me yesterday. To be honest, when I copied this piece of code, I had such a vague idea of what I was doing that I didn't even think about it. I have already fixed it in my code (not in my question, though). 2. Thank you. I copied your code. Now I only get one error. "The named parameter 'assetPath' is required, but there's no corresponding argument." It leads to @override Widget build(BuildContext context) { return ListFromCSV(); } }. What could be the reason? – Texter Jul 12 '22 at 11:29
  • I tried two variants at once. Obviously, I mistakenly commented out a line from one variant. Now I have checked again. Your code is working. No errors. Thanks a lot. – Texter Jul 12 '22 at 12:38