簡體   English   中英

如何在 Flutter/Dart 的同一屏幕中保存和加載兩個變量?

[英]How to save and load two variables in the same screen in Flutter/Dart?

這是我的代碼:

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

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

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

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Column(
        mainAxisSize: MainAxisSize.min,
        children: <Widget>[
          const SizedBox(height: 30),
          ClipRRect(
            borderRadius: BorderRadius.circular(4),
            child: Stack(
              children: <Widget>[
                Positioned.fill(
                  child: Container(
                    decoration: const BoxDecoration(
                      gradient: LinearGradient(
                        colors: <Color>[
                          Color(0xFF0D47A1),
                          Color(0xFF1976D2),
                          Color(0xFF42A5F5),
                        ],
                      ),
                    ),
                  ),
                ),
                TextButton(
                  style: TextButton.styleFrom(
                    padding: const EdgeInsets.all(16.0),
                    primary: Colors.white,
                    textStyle: const TextStyle(fontSize: 20),
                  ),
                  onPressed: () {
                    Navigator.push(
                      context,
                      MaterialPageRoute(builder: (context) => const NewGameRoute()),
                    );
                  },
                  child: const Text('New Game'),
                ),
              ],
            ),
          ),
          const SizedBox(height: 30),
          ClipRRect(
            borderRadius: BorderRadius.circular(4),
            child: Stack(
              children: <Widget>[
                Positioned.fill(
                  child: Container(
                    decoration: const BoxDecoration(
                      gradient: LinearGradient(
                        colors: <Color>[
                          Color(0xFF0D47A1),
                          Color(0xFF1976D2),
                          Color(0xFF42A5F5),
                        ],
                      ),
                    ),
                  ),
                ),
                TextButton(
                  style: TextButton.styleFrom(
                    padding: const EdgeInsets.all(16.0),
                    primary: Colors.white,
                    textStyle: const TextStyle(fontSize: 20),
                  ),
                  onPressed: () {
                    Navigator.push(
                      context,
                      MaterialPageRoute(builder: (context) => const NewGameRoute()),
                    );
                  },
                  child: const Text('Continue Game'),
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }
}


// New Game route
class NewGameRoute extends StatelessWidget {
  const NewGameRoute({key});

  @override
  Widget build(BuildContext context) {
    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];
    });
  }

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

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

  @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),
                  ],
                ),
              ],
            ),
              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),
          ),
        ),
      ),
    );
  }
}

這個實驗性應用由兩個屏幕組成:

主屏幕:

在此處輸入圖像描述

游戲畫面:

在此處輸入圖像描述

我需要保存 2 個變量:_listCount 和assetPath,以便以后我的用戶可以繼續游戲。 但與此同時,New Game 和 Continue Game 屏幕幾乎完全相同。 其實這是同一個畫面。 唯一的區別是當我的用戶開始游戲時,變量具有以下值:

int_listCount = 0;
String assetPath = "files/main.jpg";

當我的用戶點擊“繼續游戲”按鈕時,他們應該進入同一個屏幕,但變量的值應該不同。 最簡單的方法是什么?

我相信我應該遵循以下步驟:

  1. 當我單擊 OK 按鈕時,將 _listCount 和 assetPath 變量保存到設備的內存中。 為此,我需要修改此代碼:
      void _nextCSV() {
        setState(() {
          _listData = _listData;
          _listCount < _listData.length - 1
              ? _isFirstLoad
              ? _isFirstLoad = false
              : _listCount++
              : _listCount;
          assetPath =
          _listData[_listCount][1] == "" ? assetPath : _listData[_listCount][1];
        });
      }
  1. 當我單擊繼續游戲按鈕時,從設備內存中加載 _listCount 和assetPath 變量的值。 為此,我需要修改此代碼:
    onPressed: () {
                        Navigator.push(
                          context,
                          MaterialPageRoute(builder: (context) => const NewGameRoute()),
                        );
                      },

也就是說,用戶將轉到 NewGameRoute,但這些變量的值不同。 或者創建一個與 NewGameRoute 幾乎完全相同(除了我的值)的 ContinueGameRoute 是否正確? 從內存中保存和加載這些值的最簡單方法是什么?

編輯 1.使用Sparsh Jain的代碼,我有以下內容:

Launching lib\main.dart on sdk gphone64 x86 64 in debug mode...
Running Gradle task 'assembleDebug'...
lib/main.dart:168:7: Error: Expected an identifier, but got ':'.
Try inserting an identifier before ':'.
      : super(key: key);
      ^
lib/main.dart:168:24: Error: Expected '}' before this.
      : super(key: key);
                       ^
lib/main.dart:172:3: Error: Expected '{' before this.
  final int _listCount;
  ^^^^^
lib/main.dart:75:23: Error: No named parameter with the name '_listCount'.
                      _listCount: 0, assetPath: "images/01.jpg" ///What I want to pass
                      ^^^^^^^^^^
lib/main.dart:164:3: Context: Found this candidate, but the arguments don't match.
  NewGameRoute(
  ^^^^^^^^^^^^
lib/main.dart:85:69: Error: Cannot invoke a non-'const' constructor where a const expression is expected.
Try using a constructor or factory that is 'const'.
                      MaterialPageRoute(builder: (context) => const NewGameRoute()),
                                                                    ^^^^^^^^^^^^
lib/main.dart:168:20: Error: Undefined name 'key'.
      : super(key: key);
                   ^^^
lib/main.dart:168:9: Error: Method invocation is not a constant expression.
      : super(key: key);
        ^^^^
lib/main.dart:172:13: Error: Final field '_listCount' is not initialized.
Try to initialize the field in the declaration or in every constructor.
  final int _listCount;
            ^^^^^^^^^^
lib/main.dart:174:16: Error: Final field 'assetPath' is not initialized.
Try to initialize the field in the declaration or in every constructor.
  final String assetPath;
               ^^^^^^^^^


FAILURE: Build failed with an exception.

* Where:
Script 'D:\flutter\packages\flutter_tools\gradle\flutter.gradle' line: 1156

* What went wrong:
Execution failed for task ':app:compileFlutterBuildDebug'.
> Process 'command 'D:\flutter\bin\flutter.bat'' finished with non-zero exit value 1

* Try:
> Run with --stacktrace option to get the stack trace.
> Run with --info or --debug option to get more log output.
> Run with --scan to get full insights.

* Get more help at https://help.gradle.org

BUILD FAILED in 9s
Exception: Gradle task assembleDebug failed with exit code 1

編輯 2.在更有經驗的人的幫助下,我昨天修改了這段代碼。 現在它看起來像這樣,並且只有一個錯誤。 但是,它仍然不起作用。

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


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;




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



  // 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),
          ),
        ),
      ),
    );
  }
}

現在我只得到一個錯誤。

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

它導致

@override
   Widget build(BuildContext context) {
     return ListFromCSV();
   }
}

可能是什么原因?

編輯 3.這是我的代碼丟失的內容:

@override
  Widget build(BuildContext context) {
    return ListFromCSV(listCount: _listCount, assetPath: assetPath);
  }

現在它完美無缺。

您可以將variables的值從基本頁面傳遞給NewGameRoute類。

可以這樣稱呼它, NewGameRoute(10, "abc.csv");

class NewGameRoute extends StatelessWidget {
  NewGameRoute(
      {Key? key,
      required this. _listCount,
      required this. assetPath,
      : super(key: key);

  final int _listCount;

  final String assetPath;


  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'New Game',
      home: ListFromCSV(),
    );
  }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM