how to make history with textfield in flutter? - list

class _SimpleDialogState extends State<SimpleDialog> {
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
final TextEditingController _textEditingController = TextEditingController();
#override
void initState() {
super.initState();
baseurl = Prefs().geturlBase();
}
#override
Widget build(BuildContext context) {
return AlertDialog(
title: Text('Base URL'),
content: Form(
key: _formKey,
child: TextFormField(
keyboardType: TextInputType.multiline,
maxLines: null,
//controller: _textEditingController,
initialValue: baseurl,
onChanged: (val) {
setState(() {
baseurl = val;
print(baseurl);
});
},
decoration: InputDecoration(
hintText: "Please Enter Base Url",
border:
OutlineInputBorder(borderRadius: BorderRadius.circular(15)),
),
validator: (value) {
// return value!.isNotEmpty ? null : "Enter Base Url";
return Uri.parse(value.toString()).host == ''
? "Enter Base Url"
: null;
},
)),
actions: <Widget>[
Center(
child: InkWell(
onTap: () {
buildShowDialog(context);
if (_formKey.currentState!.validate()) {
baseurl = baseurl.trim();
checkBaseUrl(baseurl, context);
// Navigator.of(context).pop();
print('baseurl=====base------$baseurl');
}
},
child: Container(
width: 100,
height: 40,
padding: EdgeInsets.all(12.0),
decoration: BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.circular(20.0),
),
child: Text(
"Connect",
textAlign: TextAlign.center,
style: TextStyle(color: Colors.white),
),
),
),
)
],
);
}
}
This is a dialog box where I can change my baseURL. Now, I need history when I touch textfield, history should appear and I can able to select the data from history to text field and also able to delete history, not all history particular data from that list. how can I able to achieve this kinda logic??.

An input_history_text_field widget is automatically saved and suggested as you type.

Related

Flutter "The expression doesn't evaluate to a function, so it can't be invoked."

I am building a app to practice my Flutter skills. The app is a quiz app. I am trying to make it possible for users to add questions. I have a variable which is a list called: questions. I also have another variable called: answers (which is also a list). So they are separated, however, I have a variable for questionIndex so to display the question and assign the correct answer i use the index to define which list item is relevant.
Now I have an issue.... I succeeded in trying to add the questiontext with a function in my statefulwidget, however, trying to add an answer to the answers list is not working. It gives me the error: "The expression doesn't evaluate to a function, so it can't be invoked."
How would you solve this? Would be really thankful for some input!
The file with a StatefulWidget (containing the functions to add questions and answers):
import 'questionText.dart';
import 'buttons.dart';
import 'end.dart';
import '../pages/add_questions.dart';
import '../model/question_class.dart';
import '../model/Answer_class.dart';
class QuizPage extends StatefulWidget {
#override
State<QuizPage> createState() => _QuizPageState();
}
class _QuizPageState extends State<QuizPage> {
int questionIndex = 0;
int points = 0;
List<Widget> scoreKeeper = [];
var _questions = [
{
'Victor loves computers',
},
'Victor is learning Flutter',
'Victor\'s favorite team is Manchester United',
'Victor\'s favorite team is Chelsea'
];
List<bool> answers = [
true,
true,
false,
true,
];
void _addIndex() {
setState(() {
questionIndex = questionIndex + 1;
});
}
late bool userAnswer;
void _setUserAnswerTrue() {
setState(() {
userAnswer = true;
});
}
void _setUserAnswerFalse() {
setState(() {
userAnswer = false;
});
}
void _checkIfCorrect() {
bool correctAnswer = answers[questionIndex];
setState(() {
correctAnswer == userAnswer ? points = points + 1 : points = points;
print(points);
});
setState(
() {
correctAnswer == userAnswer
? scoreKeeper.add(
Icon(
Icons.check,
color: Colors.green,
),
)
: scoreKeeper.add(
Icon(
Icons.close,
color: Colors.red,
),
);
},
);
}
void restartQuiz() {
setState(() {
questionIndex = 0;
scoreKeeper.clear();
});
}
void addNewQuestion(String txTitle) {
final newTx = Question(
title: txTitle,
);
setState(() {
_questions.add(newTx.toString());
});
}
void addNewBool(bool txAnswer) {
final newBool = Answer(
correctAnswer: txAnswer,
);
setState(() {
answers.add(newBool());
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.grey.shade900,
actions: [
IconButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
AddQuestions(addNewQuestion, addNewBool),
),
);
},
icon: Icon(Icons.add),
),
],
),
backgroundColor: Colors.grey.shade900,
body: SafeArea(
child: Padding(
padding: const EdgeInsets.all(10.0),
child: questionIndex < _questions.length
? Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
QuestionText(_questions, questionIndex),
QuButtons(_setUserAnswerTrue, _setUserAnswerFalse,
_checkIfCorrect, _addIndex),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: Row(
children: scoreKeeper,
),
),
],
)
: EndOfQuiz(scoreKeeper, restartQuiz),
)),
);
}
}
My file containting the text inputs:
import 'package:flutter/material.dart';
class AddQuestions extends StatelessWidget {
final titleController = TextEditingController();
final answerController = TextEditingController();
final Function addQu;
final Function addBoo;
AddQuestions(this.addQu, this.addBoo);
void submitInput() {
final enteredTitle = titleController.text;
final enteredBool = answerController.text.toLowerCase();
addQu(
enteredTitle,
);
addBoo(
enteredBool,
);
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
backgroundColor: Colors.grey.shade900,
appBar: AppBar(
backgroundColor: Colors.grey.shade900,
leading: IconButton(
icon: Icon(Icons.arrow_back),
onPressed: () {
Navigator.pop(context);
},
),
),
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Padding(
padding: const EdgeInsets.all(20),
child: TextField(
controller: titleController,
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'Question Text',
),
onSubmitted: (_) => submitInput(),
),
),
Padding(
padding: const EdgeInsets.all(20),
child: TextField(
controller: answerController,
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'True/False',
),
onSubmitted: (_) => submitInput(),
),
),
FlatButton(
onPressed: () {
submitInput;
},
child: Text('Add button'),
)
],
),
),
);
}
}
The answers list is a boolean array and you are adding the newBool() as a function which is the object of Answer class.
newBool() is a function not a boolean value. And list needs a boolean value to add.

Selecting from a dropdown list and updating the same list the same time in flutter

How do I ensure that a user does not select the same security question twice by hiding the initially selected question from appearing in the second dropdown button and vice versa in flutter?. i am making a request to the same api for the questions.
Updated the question with some code snippets. Thanks
Container(
height: 60,
width: double.infinity,
decoration: BoxDecoration(
border: Border.all(color: Colors.black,
width: 1),
borderRadius: BorderRadius.circular(5),
),
child: DropdownButtonHideUnderline(
child: DropdownButton(
hint: Padding(
padding: const EdgeInsets.only(left:
20.0),
child: Text(
"Security Question Two",
style: TextStyle(
color: Colors.black,
fontSize: 16,
letterSpacing: 0.3,
fontWeight: FontWeight.w300),
),
),
itemHeight: 100,
isExpanded: true,
value: dropDownSecurityQuestionTwo,
icon: Padding(
padding: const EdgeInsets.only(right:
10.0),
child:
Icon(Icons.keyboard_arrow_down_outlined),
),
iconEnabledColor: Colors.black,
iconSize: 30,
style: TextStyle(
color: Colors.black,
),
items: questions.map((value) {
return DropdownMenuItem(
value: value['ID'].toString(),
child: Padding(
padding: const EdgeInsets.only(left:
20.0),
child: Text(
value['question'].toString(),
),
),
);
}).toList(),
onChanged: (newValue) async {
setState(() {
dropDownSecurityQuestionTwo =
newValue.toString();
print(dropDownSecurityQuestionTwo);
checkSelectedQuestion();
});
},
),
),
),
void checkSelectedQuestion(){
List newQuestions = [];
for(int i = 0; i<questions.length; i++){
print(questions[i]['ID']);
questions.removeWhere((value) => value['ID'] ==
int.parse(dropDownSecurityQuestionOne!) );
newQuestions.add(questions);}
setState(() {
questions = newQuestions ;
});}
You can add a where filter to the mapping of items to each DropDownButton, depending on the selected value of the other DropDownButton. As a result of setState, the items will be recreated if anything is selected in the other DropDownButton.
Note: This is easy to implement, but not very efficient. Items will be created and filtered every time. It will work perfectly with few items, but if you would like to do something like this with many items, you might need a more efficient approach. For example keep two items lists, and only add / remove what is affected.
Check this code and adopt it to your case:
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return const MaterialApp(
home: MyPage(),
);
}
}
class MyPage extends StatefulWidget {
const MyPage({Key? key}) : super(key: key);
#override
State<MyPage> createState() => _MyPageState();
}
class _MyPageState extends State<MyPage> {
String? _selected1;
String? _selected2;
final List<String> _set = ['Alpha', 'Bravo', 'Charlie'];
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Center(
child: Column(children: [
DropdownButton<String>(
value: _selected1,
onChanged: (String? newValue) {
setState(() {
_selected1 = newValue!;
});
},
items: _set
.map((value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
})
.where((e) => _selected2 == null || e.value != _selected2)
.toList()),
DropdownButton<String>(
value: _selected2,
onChanged: (String? newValue) {
setState(() {
_selected2 = newValue!;
});
},
items: _set
.map((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
})
.where((e) => _selected1 == null || e.value != _selected1)
.toList()),
]),
),
),
);
}
}

Flutter Firebase where query arrayContains in List [duplicate]

This question already has answers here:
Firestore search array contains for multiple values
(6 answers)
Closed 1 year ago.
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class SearchPage extends StatefulWidget {
#override
_SearchPageState createState() => _SearchPageState();
}
class _SearchPageState extends State<SearchPage> with TickerProviderStateMixin {
final searchController = TextEditingController();
final _firestore = FirebaseFirestore.instance;
static const defaultSearch = "";
String search = defaultSearch ;
void dispose() {
searchController.dispose();
super.dispose();
}
#override
void initState() {
super.initState();
searchController.addListener(searchChanged);
}
searchChanged() {
setState(() {
search = searchController.text;
});
}
#override
Widget build(BuildContext context) {
var tarifRef = _firestore
.collection("vehicles")
.where("models", arrayContains: search);
return Scaffold(
body: Container(
child: ListView(
children: <Widget>[
Expanded(
child: Container(
height: MediaQuery.of(context).size.height * 0.08,
margin: EdgeInsets.only(top: 25),
child: Text(
"Vehicles",
style: TextStyle(
fontSize: 20, fontFamily: "Quando", color: Colors.indigo),
),
),
),
Expanded(
child: Container(
margin: EdgeInsets.only(
top: 10.0, bottom: 10.0, right: 30, left: 30),
child: TextField(
keyboardType: TextInputType.text,
decoration: InputDecoration(
prefixIcon: Icon(Icons.search),
),
controller: searchController,
),
),
),
Expanded(
child: Container(
height: MediaQuery.of(context).size.height * 0.50,
child: StreamBuilder<QuerySnapshot>(
stream: tarifRef.snapshots(),
builder: (BuildContext context, AsyncSnapshot asyncsnapshot) {
if (asyncsnapshot.hasError) {
return Center(
child: Text("Error"),
);
} else {
if (asyncsnapshot.hasData) {
List<DocumentSnapshot> listOfDocumentSnapshot =
asyncsnapshot.data.docs;
return Flexible(
child: ListView.builder(
itemCount: listOfDocumentSnapshot.length,
itemBuilder: (context, index) {
return Card(
color: Colors.indigo,
child: ListTile(
title: Text(
"${listOfDocumentSnapshot[index]["name"]}",
style: TextStyle(
fontSize: 20,
color: Colors.white,
),
),
subtitle: Text(
"${listOfDocumentSnapshot[index]["models"]}",
style: TextStyle(
fontSize: 15,
color: Colors.white,
),
),
trailing: IconButton(
icon: Icon(
Icons.delete,
color: Colors.white,
),
onPressed: () async {
await listOfDocumentSnapshot[index]
.reference
.delete();
},
),
),
);
},
),
);
} else {
return Center(
child: CircularProgressIndicator(),
);
}
}
},
),
),
),
],
),
),
);
}
}
This my all code and also I have database in Firebase like this;
vehicles: [
{
"name": "Vehicle1",
"models": ["bus", "plane", "motorcycle"]
},
{
"name": "Vehicle2",
"models": ["motorcycle", "sporcar", "plane"]
},
{
"name": "Vehicle3",
"models": ["motorcycle", "plane", "bus"]
}
]
In this example I can take one input from user, I can query and display which list includes this data but I want to query more than one data is in lists or not.
For example in this code if user input bus, program display Vehicle1 list but I want user can input more than one data such as plane and motorcycle. And so when the user input the plane and motorcycle, I want it to be displayed the list of Vehicle 2 and Vehicle 3.
I try a lot of different ways but I can't found proparly solution to this problem.
I think you're looking for arrayContainsAny here:
var tarifRef = _firestore
.collection("vehicles")
.where("models", arrayContainsAny: ["bus", "plane"]);
This query will return documents whose models array contains either "bus", "plane" or both.
Also see the FlutterFire documentation for Query.where.

How to not lose a data from the list when going from one screen to another screen in flutter?

I have a class ViewTotalItemProvider which extends the ChangeNotifier. Inside the class, there is a list like this.
class ViewTotalItemProvider extends ChangeNotifier{
List<CartPlantLists> cartPlantList3 = [];
}
Additionally, there are 3 screens including class like, PlantFeatureScreen1, ParticularPlant2, CartDetais3. All are stateful widget and I am adding some items in second screen i.e. ParticularPlant2 class.
When I try to show the items from list in the second screen and the third screen it works.
But the value is not updated in the firstScreen i.e. PlantFeatureScreen1. However, when I reload the app, it shows the updated value.
why is this happening? How can I solve it?
Code
ViewTotalItemProvider
List<CartPlantLists> cartPlantList3 = [];
class ViewTotalItemProvider extends ChangeNotifier{
addQuantity(index){
cartPlantList3[index].qu++;
notifyListeners();
}
subtrachQuantity(index){
cartPlantList3[index].qu--;
notifyListeners();
}
}
firstScreen PlantFeatureScreen1 (Here I want to update the value in the very last widget)
class PlantFeatureScreen1 extends StatefulWidget {
#override
_PlantFeatureScreen1State createState() => _PlantFeatureScreen1State();
}
class _PlantFeatureScreen1State extends State<PlantFeatureScreen1> {
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider<ViewTotalItemProvider>(
create: (context) => ViewTotalItemProvider(),
child:Builder(builder: (context) {
return Column(
children: <Widget>[
TopAppBar(),
Expanded(
flex: 1,
child: Align(
alignment: Alignment(-1, 0),
child: Container(
decoration: BoxDecoration(
color: Colors.white,
),
child: Text(
"Plants",
style: TextStyle(fontSize: 30, fontWeight: FontWeight.w700),
),
),
),
),
Expanded(
flex: 5,
child: Container(
width: double.infinity,
decoration: BoxDecoration(
color: Colors.blue,
),
child: DefaultTabController(
length: 5,
child: Column(
children: [
Container(
height: 50,
width: double.infinity,
child: TabBar(
isScrollable: true,
tabs: ourAllLists.tabMaker(),
),
),
Container(
height: 317,
width: double.infinity,
decoration: BoxDecoration(color: Colors.white),
child: TabBarView(
children: ourAllLists.tabViewerMaker(context),),),
],
),
),
),
),
Padding(
padding: const EdgeInsets.fromLTRB(20, 0, 20, 20),
child: Container(
alignment: Alignment.bottomRight,
height: 120,
width: double.infinity,
child: Stack(
overflow: Overflow.visible,
children: [
Container(
height: 70,
width: 105,
decoration: BoxDecoration(
color: Color(0xFF96CA2D),
borderRadius: BorderRadiusDirectional.horizontal(
end: Radius.circular(32),
start: Radius.circular(32))),
child: Icon(FontAwesomeIcons.shoppingBag,color:Colors.white,size:30),
),
Positioned(
// top: 0,
bottom: 50,
right: 0,
child: Consumer<ViewTotalItemProvider>(
builder: (context, value, child){
return Container(
height: 35,
width: 35,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(50),
border: Border.all(color: Color(0xFF96CA2D),width: 4)
),
child: Center(child: Text(ourAllLists.totalquantity().toString(),style:TextStyle(fontSize: 20,color: Color(0xFF96CA2D)))),
);
}),
),
],
),
),
)
],
);
})
);
}
}
secondScreen ParticularPlant2
class ParticularPlant2 extends StatefulWidget {
final indexNumber;
ParticularPlant2({#required this.indexNumber});
#override
_ParticularPlant2State createState() => _ParticularPlant2State();
}
class _ParticularPlant2State extends State<ParticularPlant2> {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: SafeArea(
child: Scaffold(
body: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TopAppBar(),
Container(
decoration: BoxDecoration(
color: Colors.red,
borderRadius: BorderRadiusDirectional.only(
bottomStart: Radius.circular(50),
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
ourAllLists
.mainListAllPlantDetailsList1[widget.indexNumber].pN,
style: kPlantNameStyle,
),
Text(
ourAllLists
.mainListAllPlantDetailsList1[widget.indexNumber].ca
.toUpperCase(),
style: TextStyle(
fontSize: 15,
),
),
Text(
"\$" +
ourAllLists
.mainListAllPlantDetailsList1[widget.indexNumber]
.pr
.toString(),
style: kItemPrice,
),
SizedBox(height: 100),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Container(
height: 80,
width: 80,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(50)),
child: Icon(
FontAwesomeIcons.flag,
color: Color(0xFF9DCD3C),
),
),
SizedBox(
height: 50,
),
FlatButton(
onPressed: () {
final tile = cartPlantList3.firstWhere(
(item) =>
item.pN ==
ourAllLists
.mainListAllPlantDetailsList1[
widget.indexNumber]
.pN,
orElse: () => null);
if (tile != null) {
} else {
cartPlantList3.add(
CartPlantLists(
quantity: 1,
plantName: ourAllLists
.mainListAllPlantDetailsList1[
widget.indexNumber]
.pN,
category: ourAllLists
.mainListAllPlantDetailsList1[
widget.indexNumber]
.ca,
price: ourAllLists
.mainListAllPlantDetailsList1[
widget.indexNumber]
.pr,
),
);
}
print(cartPlantList3.length);
},
child: Container(
height: 80,
width: 80,
decoration: BoxDecoration(
color: Color(0xFF9DCD3C),
borderRadius: BorderRadius.circular(50)),
child: Icon(FontAwesomeIcons.shoppingBag,
color: Colors.white),
),
)
],
),
Container(
height: 250,
child: Image(image: AssetImage("assets/tulip.png")),
)
],
)
],
),
)
],
),
),
),
);
}
}
It seems like you are using Provider the wrong way. The best way to do this in your scenario is to wrap MaterialApp inside MyApp() in your main.dart file with MultiProvider. Try something like this: https://pub.dev/packages/provider#multiprovider You can place a ChangeNotifierProvider inside it.
return MultiProvider(
providers: [
ChangeNotifierProvider<ViewTotalItemProvider>(
create: (context) => ViewTotalItemProvider()),
],
child: MaterialApp(...)
);
Also, you have to place a getter and setter in your Model. Here is an example:
class ImageModel extends ChangeNotifier {
String _base64Image;
get base64Image => _base64Image;
set base64Image(String base64Image) {
_base64Image = base64Image;
notifyListeners();
}
}
I would also recommend using Selector instead of Consumer (Ideally, you should use Selector instead of Consumer so that the widget only rebuilds if the value its listening to changes) Here is an example based on the model above:
#override
Widget build(BuildContext context) {
//other widgets
Selector<ImageModel, String>(
selector: (_, model) => model.base64Image,
builder: (_, image, __) {
return Text(image);
},
);
}
)
}
Here is how you can get and set it using a RaisedButton:
class _PlantFeatureScreen1State extends State<PlantFeatureScreen1> {
final itemModel;
List<CartPlantLists> myList=[];
#override
Widget build(BuildContext context) {
itemModel = Provider.of<ViewTotalItemProvider>(context,listen:false);
print(itemModel.yourVariable); //getting the value
return Container(
child: RaisedButton(
child:Text("Set Item");
onPressed:(){
itemModel.yourVariable=myList; //setting the value
},
),
);
}
}
Hope this helps! Good Luck!
Step 1:
add the dependency for the provider pattern in the pubspec.yaml file
dependencies:
flutter:
sdk: flutter
provider: ^4.1.2
Step 2:
create provider in seperate file :
class ViewTotalItemProvider with ChangeNotifier{
List<CartPlantLists> _cartPlantList1 = [];
get cartPlantList1 => _cartPlantList1 ;
set cartPlantList1 (List<CartPlantLists> selected){
_cartPlantList1 = selected;
notifyListeners();
}
}
step 3:
Use MultiProvider to wrap the MaterialApp widget in main.dart.
void main() => runApp(
MultiProvider (providers: [
ChangeNotifierProvider<ViewTotalItemProvider>.value(value:
ViewTotalItemProvider()),
],
child: MyApp()
)
);
class MyApp extends StatelessWidget {
Widget build(BuildContext context) {
return MaterialApp(
home: HomePage(),
);
}
}
Step 4:
use provider in your screen PlantFeatureScreen1 :
class PlantFeatureScreen1 extends StatefulWidget {
#override
_PlantFeatureScreen1State createState() => _PlantFeatureScreen1State();
}
class _PlantFeatureScreen1State extends State<PlantFeatureScreen1> {
var viewTotalItemProvider;
#override
Widget build(BuildContext context) {
viewTotalItemProvider = Provider.of<ViewTotalItemProvider>(context);
return Scaffold(
.......
);
}
}
step 5:
get cartPlantList1.
List<CartPlantLists> list = viewTotalItemProvider.cartPlantList1;
step 6 : set cartPlantList1.
List<CartPlantLists> list = [];
...
viewTotalItemProvider.cartPlantList1 = list;
similarly u can use for other two classes.

change containerColor from a list

I have previously asked a question regarding lists in Flutter. I got good help but new problems arose within the same list. Since this new probelm is of other character then the initial question I made this new question.
I have a list (the code below is simplified from my working-code to make my problem clearer) of blue colored containers.
When the user types in 5 and press the 'submit'-button the color of the first container should change to green (if not 5 the button should turn red).
The second time the user press the 'submit'-button the second container should change color. And so on...
The problem I'm facing is that I can't get my increment to the list to work.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'listing 4',
theme: ThemeData(primarySwatch: Colors.blue),
home: FirstScreen(),
);
}
}
class FirstScreen extends StatefulWidget {
#override
_FirstScreenState createState() => _FirstScreenState();
}
class _FirstScreenState extends State<FirstScreen> {
int sum = 5;
String userAnswer;
String correction = "";
var _controller = new TextEditingController();
int _counter = 1;
List<Color> colors = [Colors.blue, Colors.blue, Colors.blue];
submitPressed(int index) {
if (userAnswer == sum.toString()) {
setState(() {
correction = sum.toString();
colors[index] = Colors.green;
});
} else {
setState(() {
correction = sum.toString();
colors[index] = Colors.red;
});
}
}
Widget myTextField() {
return Container(
width: 50.0,
child: TextField(
controller: _controller,
textAlign: TextAlign.center,
autofocus: true,
keyboardType: TextInputType.number,
onChanged: (val) {
userAnswer = val;
},
),
);
}
Widget myListBuilder() {
return Container(
height: 50.0,
width: 300.0,
child: Padding(
padding: const EdgeInsets.all(10.0),
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: 3,
itemBuilder: buildContainer,
),
),
);
}
Widget buildContainer(BuildContext context, int index) {
return Container(
child: Padding(
padding: const EdgeInsets.only(top: 10.0),
child: Container(
height: 20.0,
width: 15.0,
decoration: BoxDecoration(
color: colors[index], //this is the important line
borderRadius: BorderRadius.all(Radius.circular(8.0))),
),
));
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: Text('Listing 4'),
),
body: Container(
child: Center(
child: Column(
children: <Widget>[
Padding(
padding: EdgeInsets.only(top: 10.0),
child: Text('Correct answer is 5',
style: TextStyle(fontSize: 20.0)),
),
myTextField(),
RaisedButton(
child: Text('Submit'),
onPressed: () {
setState(() {
submitPressed(0); //This will naturally only give index 0
});
},
),
myListBuilder(),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
buildContainer(context, 0),
buildContainer(context, 1),
buildContainer(context, 2)
],
),
RaisedButton(
child: Text('Next'),
onPressed: () {
_counter++;
_controller.clear();
myTextField();
},
),
Text('This should be container no: $_counter'),
],
),
),
),
);
}
}
I can't figure out why you have this
submitPressed(0);
This code works:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'listing 4',
theme: ThemeData(primarySwatch: Colors.blue),
home: FirstScreen(),
);
}
}
class FirstScreen extends StatefulWidget {
#override
_FirstScreenState createState() => _FirstScreenState();
}
class _FirstScreenState extends State<FirstScreen> {
int sum = 5;
String userAnswer;
String correction = "";
var _controller = new TextEditingController();
int _counter = 0;
List<Color> colors = [Colors.blue, Colors.blue, Colors.blue];
submitPressed(int index) {
if (userAnswer == sum.toString()) {
setState(() {
correction = sum.toString();
colors[index] = Colors.green;
});
} else {
setState(() {
correction = sum.toString();
colors[index] = Colors.red;
});
}
}
Widget myTextField() {
return Container(
width: 50.0,
child: TextField(
controller: _controller,
textAlign: TextAlign.center,
autofocus: true,
keyboardType: TextInputType.number,
onChanged: (val) {
userAnswer = val;
},
),
);
}
Widget myListBuilder() {
return Container(
height: 50.0,
width: 300.0,
child: Padding(
padding: const EdgeInsets.all(10.0),
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: 3,
itemBuilder: buildContainer,
),
),
);
}
Widget buildContainer(BuildContext context, int index) {
return Container(
child: Padding(
padding: const EdgeInsets.only(top: 10.0),
child: Container(
height: 20.0,
width: 15.0,
decoration: BoxDecoration(
color: colors[index], //this is the important line
borderRadius: BorderRadius.all(Radius.circular(8.0))),
),
));
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: Text('Listing 4'),
),
body: Container(
child: Center(
child: Column(
children: <Widget>[
Padding(
padding: EdgeInsets.only(top: 10.0),
child: Text('Correct answer is 5',
style: TextStyle(fontSize: 20.0)),
),
myTextField(),
RaisedButton(
child: Text('Submit'),
onPressed: () {
setState(() {
submitPressed(_counter);
});
},
),
myListBuilder(),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
buildContainer(context, 0),
buildContainer(context, 1),
buildContainer(context, 2)
],
),
RaisedButton(
child: Text('Next'),
onPressed: () {
setState(() {
_counter++;
});
_controller.clear();
myTextField();
},
),
Text('This should be container no: ${_counter +1}'),
],
),
),
),
);
}
}
I changed the _counter to act like an index and use it as the parameter of the method submitPressed.
I also put the increment in a setState, or you saw the new number only after hitting the Submit button.