currently learning flutter and trying to do a simple game.
I have list with prices and product name.
My idea is to display a random image, and someone tries to guess the price.
Currently I'm stuck on the comparing the input price with the price on the list.
This is what I currently have
class MyCustomForm extends StatefulWidget {
const MyCustomForm({Key? key}) : super(key: key);
@override
_MyCustomFormState createState() => _MyCustomFormState();
}
class _MyCustomFormState extends State<MyCustomForm> {
final myController = TextEditingController();
@override
void initState() {
super.initState();
@override
void dispose() {
myController.dispose();
super.dispose();
}
}
@override
Widget build(BuildContext context) {
int randomIndex = Random().nextInt(products.length);
return Scaffold(
appBar: AppBar(
title: const Text(
"Guess the Price!",
style: TextStyle(fontFamily: "Pacifico"),
),
),
backgroundColor: Colors.white,
body: InkWell(
child: Container(
padding: const EdgeInsets.all(40),
child: Column(
children: <Widget>[
Spacer(),
Container(
child: Text(
'${products[randomIndex].productName}',
style: TextStyle(
fontSize: 30,
),
)),
Container(
child: TextFormField(
controller: myController,
keyboardType: TextInputType.number,
inputFormatters: <TextInputFormatter>[
FilteringTextInputFormatter.allow(RegExp(r'[0-9]')),
],
decoration: InputDecoration(
hintText: "The price is ${products[randomIndex].productPrice}", //debuging
))),
Spacer(),
Container(
child: Text((() {
if ({products[randomIndex].productPrice} == {myController.text}) {
return "The price is correct!";
}
return "The price is wrong!";
})()),
),
],
),
),
),
);
}
}
What should I add to do the work? Should I add a listener, so when the text changes, he auto updates the value of the myController.text , or should I go through other ways?
Sorry if this is a newbie error, but currently searching for solutions!
CodePudding user response:
First, you need to move randomIndex outside of the build method otherwise it would always change when the state changes and you can't compare it to user input.
I am not sure exactly what you want but I think this will give you a hint how to do it.
class MyCustomForm extends StatefulWidget {
const MyCustomForm({Key? key}) : super(key: key);
@override
_MyCustomFormState createState() => _MyCustomFormState();
}
class _MyCustomFormState extends State<MyCustomForm> {
final myController = TextEditingController();
String guessText = "";
@override
void initState() {
super.initState();
}
@override
void dispose() {
myController.dispose();
super.dispose();
}
int randomIndex = Random().nextInt(products.length);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text(
"Guess the Price!",
style: TextStyle(fontFamily: "Pacifico"),
),
),
backgroundColor: Colors.white,
body: InkWell(
child: Container(
padding: const EdgeInsets.all(40),
child: Column(
children: <Widget>[
Spacer(),
Container(
child: Text(
'${products[randomIndex].productName}',
style: TextStyle(
fontSize: 30,
),
)),
Container(
child: TextFormField(
controller: myController,
onChanged: (value) {
if (products[randomIndex].productPrice == value) {
guessText = "The price is correct!";
setState(() {
});
}
},
keyboardType: TextInputType.number,
inputFormatters: <TextInputFormatter>[
FilteringTextInputFormatter.allow(RegExp(r'[0-9]')),
],
decoration: InputDecoration(
hintText: "The price is ${products[randomIndex].productPrice}", //debuging
))),
Spacer(),
Container(
child: Text(guessText),
),
],
),
),
),
);
}
}
CodePudding user response:
Below is a working solution. There were quite a few changes, so have a look.
You need to have a button that gives a user the chance to move to the next product (or random). Also, you call product[..].productPrice
--this is unnecessary because you should call product[..].price
.
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class Product {
final String name;
final int price;
Product(this.name, this.price);
}
class MyCustomForm extends StatefulWidget {
const MyCustomForm({Key? key}) : super(key: key);
@override
_MyCustomFormState createState() => _MyCustomFormState();
}
class _MyCustomFormState extends State<MyCustomForm> {
final myController = TextEditingController();
List<Product> products = [
Product('p1', 5),
Product('p2', 10),
];
int productIndex = 0;
int enteredPrice = 0;
@override
void initState() {
super.initState();
@override
void dispose() {
myController.dispose();
super.dispose();
}
}
@override
Widget build(BuildContext context) {
int randomIndex = Random().nextInt(products.length);
return Scaffold(
appBar: AppBar(
title: const Text(
"Guess the Price!",
style: TextStyle(fontFamily: "Pacifico"),
),
),
backgroundColor: Colors.white,
body: InkWell(
child: Container(
padding: const EdgeInsets.all(40),
child: Column(
children: <Widget>[
const Spacer(),
Text(
products[productIndex].name,
style: const TextStyle(
fontSize: 30,
),
),
TextFormField(
controller: myController,
onChanged: (_) {
enteredPrice = int.parse(myController.text);
setState(() {});
},
keyboardType: TextInputType.number,
inputFormatters: <TextInputFormatter>[
FilteringTextInputFormatter.allow(
RegExp(r'[0-9]'),
),
],
),
const Spacer(),
Text(
(() {
return checkEnteredPrice(0);
})(),
style: const TextStyle(fontSize: 20),
),
const Spacer(),
ElevatedButton(
onPressed: () {
productIndex ;
setState(() {});
},
child: const Text('Next Product'))
],
),
),
),
);
}
String checkEnteredPrice(int productIndex) {
if (products[productIndex].price == enteredPrice) {
return "The price is correct!";
} else {
return "The price is wrong!";
}
}
}
CodePudding user response:
I wrote an example here, check the comment for descrition. Check images for demo result.
For your code, i have some advice:
- do not
(){}()
, use? :
or something else instead, it look too long and make me confuse. - recomend to separate your logic and your render, more specific is put
Random
inbuild
that causerandomIndex
changes everytime widget rendered. put them in some function that caller able.
import 'package:flutter/material.dart';
import 'dart:math';
void main() => runApp(MyApp());
const products = <Map<String, dynamic>>[
{'name': 'HotDog', 'price': 5},
{'name': 'Televison', 'price': 699},
{'name': 'Carrot', 'price': 10},
];
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(primarySwatch: Colors.blue),
home: const App(),
);
}
}
class App extends StatefulWidget {
const App({Key? key}) : super(key: key);
@override
_AppState createState() => _AppState();
}
class _AppState extends State<App> {
final controller = TextEditingController();
int? randomIndex; // stored random index product
String? answer; // stored your answer
bool get submitAnswered =>
answer != null; // getter check user was answerd yet?
int? get correctPrice => randomIndex != null
? products[randomIndex!]['price']
: null; // getter to get correct answer
// function to generate randomIndex, reset your answer
void getRandomIndex() {
int? newIndex;
do {
newIndex = Random().nextInt(products.length);
} while (newIndex == randomIndex);
setState(() {
randomIndex = newIndex;
answer = null;
controller.text = '';
});
}
// function to submit your answer
void onSubmitted(String value) {
setState(() {
answer = value;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text(
"Guess the Price!",
style: TextStyle(fontFamily: "Pacifico"),
),
),
backgroundColor: Colors.white,
body: Container(
padding: const EdgeInsets.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// Button that generate new randomIndex
ElevatedButton(
onPressed: getRandomIndex,
child: const Text('Get random product'),
),
// Only render when have randomIndex
if (randomIndex != null) ...[
// Display name of prouct
Center(
child: Text(products[randomIndex!]['name']),
),
// Only render when not answered yet, show text input and submit button
if (!submitAnswered) ...[
TextField(
controller: controller,
onSubmitted: onSubmitted,
decoration: const InputDecoration(
hintText: 'your price',
),
),
ElevatedButton(
onPressed: () => onSubmitted(controller.text),
child: const Text('Submit your price'),
),
] else
// Only render when answered, showing your result, correct or not
Center(
child: Text(int.tryParse(answer!) == correctPrice
? 'Correct price ($correctPrice)'
: 'Wrong price, your price is $answer and correct price is $correctPrice'),
),
],
],
)),
);
}
}