Here is my code:
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),
),
),
),
);
}
}
This experimental app consists of two screens:
Main screen:
Game screen:
I need to save 2 variables: _listCount and assetPath so that later on my users can continue the game. But at the same time, the New Game and Continue Game screens are almost identical. In fact, this is the same screen. The only difference is that when my user starts the game, the variables have the following values:
int_listCount = 0;
String assetPath = "files/main.jpg";
And when my user clicks on the "Continue game" button, they should get to the same screen, but the values of the variables should be different. What is the easiest way to do this?
I believe I should follow these steps:
void _nextCSV() {
setState(() {
_listData = _listData;
_listCount < _listData.length - 1
? _isFirstLoad
? _isFirstLoad = false
: _listCount++
: _listCount;
assetPath =
_listData[_listCount][1] == "" ? assetPath : _listData[_listCount][1];
});
}
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => const NewGameRoute()),
);
},
That is, the user will go to NewGameRoute, but with different values for these variables. Or would it be correct to create a ContinueGameRoute that is almost exactly the same as NewGameRoute (other than my values)? What is the easiest way to save and load these values from memory?
Edit 1. Using Sparsh Jain 's code, I have the following:
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
Edit 2. With the help of more experienced people I modified this code yesterday. Now it looks like this and has only one error. It still doesn't work, though.
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),
),
),
),
);
}
}
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?
Edit 3. Here's what my code was missing:
@override
Widget build(BuildContext context) {
return ListFromCSV(listCount: _listCount, assetPath: assetPath);
}
Now it works perfect.
You can pass the value of variables
from the base page to the NewGameRoute
class.
can call it like, 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(),
);
}
}
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.