简体   繁体   中英

How to pass data to the class of another screen in Flutter/Dart?

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.

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 aboutMaterialApp

  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();
  }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM