How to remove specific Row widget on action - flutter

How can I remove specific Row in my screen in Flutter Web Page?
I have 2 Rows in StatefulWidget "EditForm2". Both rows have Text, TextFormField and also Button to remove whole row.
What is a good way to achieve this? I assume that I have to use setstate() method and removeAt() on
Row table, but I don't know how to use this.
I want to make dynamic form where user can delete and add input controls.
import 'package:flutter/material.dart';
class EditForm2 extends StatefulWidget {
#override
_EditForm2State createState() => _EditForm2State();
}
class _EditForm2State extends State<EditForm2> {
var Rows = <Row>[];
Row RowFsLink;
Row RowGeoInfo;
#override
Widget build(BuildContext context) {
///first Row
RowFsLink = new Row(children: [
Expanded(
flex: 3,
child: Container(
margin: const EdgeInsets.only(left: 30.0, right: 30.0),
child: Text('Link',
style: TextStyle(
color: Colors.black54,
fontSize: 20.0,
letterSpacing: 0,
fontWeight: FontWeight.normal,
)),
),
),
Expanded(
flex: 6,
child: Container(
margin: const EdgeInsets.only(right: 30.0),
child: TextFormField(initialValue: 'test link'))),
Container(
margin: const EdgeInsets.only(right: 30.0),
child: Ink(
decoration: ShapeDecoration(
color: Colors.red,
shape: CircleBorder(),
),
child: IconButton(
icon: Icon(
Icons.remove,
color: Colors.white,
),
onPressed: () {},
),
),
),
]);
Rows.add(RowFsLink);
///second Row
RowGeoInfo = new Row(children: [
Expanded(
flex: 3,
child: Container(
margin: const EdgeInsets.only(left: 30.0, right: 30.0, bottom: 50),
child: Text('Geo',
style: TextStyle(
color: Colors.black54,
fontSize: 20.0,
letterSpacing: 0,
fontWeight: FontWeight.normal,
)),
),
),
Expanded(
flex: 6,
child: Container(
margin: const EdgeInsets.only(right: 30.0, bottom: 50),
child: TextFormField(initialValue: '0.50;0.44'))),
Container(
margin: const EdgeInsets.only(right: 30.0),
child: Ink(
decoration: ShapeDecoration(
color: Colors.red,
shape: CircleBorder(),
),
child: IconButton(
icon: Icon(
Icons.remove,
color: Colors.white,
),
onPressed: () {},
),
),
),
]);
Rows.add(RowGeoInfo);
return Column(children: this.Rows);
}
}

Check the state variable isVisible before calling the Rows.add method:
var _isVisible = true;
...
onPressed: () {
setState(() {
_isVisible = false;
});
},
...
Inside the build method:
if (_isVisible) {
Rows.add(RowGeoInfo);
}
This will dynamically add / remove the row at each refresh. Everytime you call setState the page is refreshed.

First declare a bool variable. Inside the onPressed you want to change the variable on click, we wrap it in a setState so that the widgets rebuild themselves.
bool isVisible = false;
onPressed: () {
setState(() {
isVisible = true;
});
},
To hide or show the Row we simply do this.
(isVisible)? Row(children: [],) : Container()
This means that if isVisible = true we show the Row() if its false we show an empty container.

Related

Passing data from AlertDialog to same screen

I'm having some trouble simply sending data from AlertDialog to our mainscreen that is _MyHomePageState and into the defined Text widget saying "Paste here!".
I also have a few questions regarding passing data in this scenario (where we are sending data from pop up window to same or other screen):
1.) Is using AlertDialog widget in this scenario even the correct technique?
2.) What's the correct method when passing input data and displaying it, do we first save it into an array and then retrieve value from array? Do we use stack or some other array method?
3.) Why or why not should I put my logic into the _MyHomePage class or it doesn't matter?
4.) Should I use custom component that I call from some other file for pop up button/window? (feels like there's just a bunch of stuff code wise that could be elsewhere on its own in its own file)
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
GlobalKey<FormState> _formKey = GlobalKey<FormState>();
Future<void> showInformationDialog(BuildContext context) async {
return await showDialog(context: context,
builder: (context) {
final TextEditingController _textEditingController = TextEditingController();
bool isChecked = false;
final TextEditingController _testEE = TextEditingController();
return StatefulBuilder(builder: (context, setState) {
return AlertDialog(
content: Form(
key: _formKey,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
TextFormField(
controller: _testEE,
validator: (value) {
//check if value is empty
return value.isNotEmpty ? null : "Invalid Field";
},
decoration: InputDecoration(hintText: "Enter text"),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text("Choice"),
Checkbox(value: isChecked, onChanged: (checked) {
setState((){
isChecked = checked;
});
})
],
)
],
)),
actions: <Widget>[
TextButton(
child: Text("Okay"),
onPressed: () {
var _test = _testEE.text;
print("test?" + _test);
if(_formKey.currentState.validate()) {
Navigator.of(context).pop();
}
},
)
],
);
});
});
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.teal[800],
body: ListView(
children: <Widget>[
Padding(
padding: EdgeInsets.only(top: 15.0, left: 40.0),
child: Row(
children: <Widget>[
Text('Check List',
style: TextStyle(
fontFamily: 'Montserrat',
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 25.0)),
IconButton(
padding: EdgeInsets.only(left: 140.0),
icon: Icon(Icons.menu),
color: Colors.white,
onPressed: () {},
)
],
),
),
SizedBox(height: 15.0),
Container(
height: MediaQuery.of(context).size.height - 100.0,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(topLeft: Radius.circular(75.0)),
),
child: ListView(
primary: false,
padding: EdgeInsets.only(left: 35.0, right: 35.0),
children: <Widget>[
Padding(
padding: EdgeInsets.only(top: 25.0),
child: Container(
height: MediaQuery.of(context).size.height - 300.0,
child: ListView(children: [
Padding(
padding: const EdgeInsets.only(top: 5.0),
child: Text('Test 1',
style: TextStyle(
fontFamily: 'Montserrat',
color: Colors.black,
fontWeight: FontWeight.bold,
fontSize: 15.0)),
),
Padding(
padding: const EdgeInsets.only(top: 5.0),
child: Text("Paste here!",
style: TextStyle(
fontFamily: 'Montserrat',
color: Colors.black,
fontWeight: FontWeight.bold,
fontSize: 15.0)),
),
//_buildFoodItem('assets/plate5.png', 'Berry bowl', '\$24.00')
]))),
//Button Row
Padding(
padding: const EdgeInsets.only(top: 60.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
SizedBox(
width: 75.0,
height: 75.0,
child: ElevatedButton(
onPressed: () async {
await showInformationDialog(context);
},
child: Text("Add"),
style: ElevatedButton.styleFrom(
side: BorderSide(width: 2.0, color: Colors.black),
shape: CircleBorder(),
padding: EdgeInsets.all(20),
primary: Colors.white, // <-- button color
onPrimary: Colors.black, // <-- splash color
),
),
),
Returning a parameter from a pushed screen or dialog is simple.
The method pop() you used accepts a optional result parameter:
Navigator.pop(context, _test); // _test will be returned
The documentation of this method can be read here.
Use this to return the previous screen the value you want. You need to use await and keep the result in a variable:
onPressed: () async {
String result = await showInformationDialog(context);
setState((){
myText=result;
});
},
Remember to declare myText inside your State class:
class _MyHomePageState extends State<MyHomePage> {
String myText = ''; // add this.
And use this variable where you need it:
[...]
child: Text(myText,
[...]
You can read more about it in this cookbook from Flutter team.
Ps: About the other questions, most of them are opinion based. They are project decisions and each have pros and cons. I believe that if this is a simple project it won't matter so much. If you need to dive deeper in these topics I suggest you to create other questions, since they are unrelated to this one.

Change state from another widget in flutter?

I am trying to make a cart icon with a text of the number of items in the cart. This requires a state refresh when state refreshes in another widget. Even though not recommended, I tried setState(), but as warned the widget was not mounted so setState() was called on null.
Then I came to know about Value listenable from this post How to set state from another widget?
I tried this, but it says "NoSuchMethodError: the getter 'value' was called on null, maybe my implementation was wrong.
heres my code:
var menuJson = [];
var isLoading = true;
class CartIcon extends StatefulWidget {
const CartIcon({Key key2}) : super(key: key2);
#override
_CartIcon createState() => _CartIcon();
}
class _CartIcon extends State<CartIcon> {
#override
Widget build(BuildContext context) {
var filteredList = List();
for (var item in menuJson) {
if (item["quantity"] > 0) {
filteredList.add(item);
}
}
return Padding(
padding: const EdgeInsets.only(top: 35, right: 8),
child: Container(
width: AppBar().preferredSize.height - 12,
height: AppBar().preferredSize.height - 12,
color: Colors.pink,
child: Material(
color: Colors.transparent,
child: InkWell(
borderRadius: BorderRadius.circular(AppBar().preferredSize.height),
child: Stack(
children: <Widget>[
IconButton(
icon: Icon(
Icons.shopping_cart,
color: Colors.white,
),
onPressed: null,
),
filteredList.length == 0
? Container()
: Positioned(
child: Stack(
children: <Widget>[
Icon(Icons.brightness_1,
size: 20.0, color: Colors.green[800]),
Positioned(
top: 3.0,
right: 4.0,
child: Text(
filteredList.length.toString(),
style: TextStyle(
color: Colors.white,
fontSize: 11.0,
fontWeight: FontWeight.w500),
))
],
)),
],
),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => CartPage()),
);
},
),
),
),
);
}
}
class Salads extends StatefulWidget {
const Salads({Key key2}) : super(key: key2);
#override
_Salads createState() => _Salads();
}
class _Salads extends State<Salads> {
final _counter = new ValueNotifier(0);
plus(index) {
var quant = menuJson[index]["quantity"];
quant++;
menuJson[index]["quantity"] = quant;
setState(() {});
}
minus(index) {
var quant = menuJson[index]["quantity"];
quant--;
if (quant < 0) {
quant = 0;
}
menuJson[index]["quantity"] = quant;
setState(() {});
}
#override
Widget build(BuildContext context) {
var filteredList = List();
for (var item in menuJson) {
if (item["category_name"] == "Salads") {
filteredList.add(item);
}
}
if (isLoading) {
return Center(
child: new CircularProgressIndicator(),
);
} else {
return Container(
color: Colors.green,
child: ListView.builder(
itemCount: filteredList.length,
itemBuilder: (context, index) {
return Card(
child: Padding(
padding: const EdgeInsets.only(
top: 10.0, bottom: 10.0, left: 10.0, right: 10.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Container(
padding: EdgeInsets.only(
left: 5, top: 5, bottom: 30),
child: Text(
filteredList[index]["dish_name"],
style: TextStyle(fontSize: 20),
textAlign: TextAlign.left,
),
),
Container(
padding: EdgeInsets.only(
right: 5, top: 5, bottom: 30),
child: Text(
'\u{20B9} ' +
filteredList[index]["price"]
.toString(),
style: TextStyle(
color: Colors.grey.shade600,
fontSize: 20),
textAlign: TextAlign.right,
)),
]),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
RawMaterialButton(
onPressed: () =>
plus(filteredList[index]["index"]),
child: new Icon(
Icons.add,
color: Colors.black,
),
fillColor: Colors.white,
shape: CircleBorder(),
),
Text(filteredList[index]["quantity"].toString(),
style: new TextStyle(fontSize: 40.0)),
RawMaterialButton(
onPressed: () =>
minus(filteredList[index]["index"]),
child: new Icon(
const IconData(0xe15b,
fontFamily: 'MaterialIcons'),
color: Colors.black,
),
fillColor: Colors.white,
shape: CircleBorder(),
padding: EdgeInsets.all(0),
)
])
],
)));
}),
);
}
}
}
Since cart icon is in the app bar, it is higher in the widget tree.
How can I make such that when + is pressed in 'Salads' the CartIcon state updates in the appbar? Right now it updates the state when i tap on the cart button.
Maybe use a Global Key?
GlobalKey<_CartIcon> cartKey = GlobalKey<_CartIcon>();
When making your CartIcon insert the globalKey.
Make a new Method inside _CartIcon:
refresh(){
setState((){})
}
and when you want to refresh your CartIcon call:
cartKey.currentState.refresh();

How to add a plus Button in ListView Builder fetches the data from SQLite in Flutter

I have a ListView Builder where I have one Stateful Widget. I want to add a plus Button as Widget inside the ListView Item. What I am doing is that, I have added a number of records in SQLite when creating the database, and I have added a plus Icon and an empty as record/row to the database. So I am fetching the data from there. The Plus Button(Widget) is displaying as I expect but when update the data into the database the Button is not Showing at the Expected position, Because I want it to display at the end of all the items.
class CategoriesScreen extends StatefulWidget {
#override
_CategoriesScreenState createState() => _CategoriesScreenState();
}
class _CategoriesScreenState extends State<CategoriesScreen> {
List<Map<String,dynamic>> spendingCategoriesList=[] ;
DatabaseHelper helper=DatabaseHelper();
#override
Widget build(BuildContext context) {
getData();
return Scaffold(
backgroundColor: Color(0xFF343641),
body: Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height-100,
margin: EdgeInsets.only(top: 40.0),
child: Column(
children: <Widget>[
Container(
width:MediaQuery.of(context).size.width ,
height: 30.0,
margin: EdgeInsets.only(left: 20.0),
child: Row(
children: [
GestureDetector(
onTap:(){Navigator.pop(context);},
child: Icon(
Icons.close,
color: Color(0xFFE44663),
size: 24.0,
),
),
Padding(
padding: EdgeInsets.only(left:MediaQuery.of(context).size.width*0.3),
child: Text('Categories',style: TextStyle(color: Colors.white,fontWeight: FontWeight.normal,fontSize: 15.0,),),
),
],
),
),
Expanded(
child: GridView.builder(
itemCount: spendingCategoriesList.length,
gridDelegate: new SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3), itemBuilder: (context,index){
AddTransactionsModel transactionModel= new AddTransactionsModel(spendingCategoriesList[index]['CategoryImage'],spendingCategoriesList[index]['categoryName']);
return AddTransactionItem(transactionModel);
}),
),
],
),
),
);
}
void getData() async{
spendingCategoriesList=await helper.getNoteMapList();
setState(() {
spendingCategoriesList=spendingCategoriesList;
});
}
Here is the AddTransactionGridItem;
class _AddTransactionItemState extends State<AddTransactionItem> {
var imageSelectIndex;
String categoryName;
String categoryImage;
#override
Widget build(BuildContext context) {
print(
'Hello dear ! icon Number ${widget.transactionModel.iconNumber} and here is Text ${widget.transactionModel.categoryNumber} ');
return Container(
child: Column(
children: <Widget>[
InkWell(
onTap: widget.transactionModel.categoryNumber == ''
? () {
showAddCategoryDialogue();
}
: () {
setState(() {
categoryName=widget.transactionModel.categoryNumber;
categoryImage=widget.transactionModel.iconNumber;
print('categoryName $categoryName And categoryImage $categoryImage');
String cate='$categoryName&$categoryImage';
Navigator.pop(context,cate);
});
},
child: Container(
width: 72.0,
height: 72.0,
decoration: BoxDecoration(
color: Color(0xffC4C4C4).withOpacity(0.2),
borderRadius: BorderRadius.all(Radius.circular(12.0)),
border: widget.transactionModel.categoryNumber == ''
? Border.all(width: 0.3, color: Colors.white)
: Border.all(width: 0.0),
),
child: Center(
child: Image.asset('${widget.transactionModel.iconNumber}')),
),
),
SizedBox(
height: 10.0,
),
Text(
widget.transactionModel.categoryNumber,
style: TextStyle(
color: Colors.white,
fontSize: 16.0,
fontWeight: FontWeight.w600,
fontFamily: 'Rajdhani',
fontStyle: FontStyle.normal),
)
],
),
);
}
AboveContainer is the ListView.Builder() Item .

Multiple Selection of ListTile

I am new to Flutter here i'm trying to select all the square boxes, given below is the code for single selection of ListTile when one tile is selected it changes it's background color to redAccent, but i need code for multiple selection where i can select all three ListTile or either two ListTile and not only one
class MultiSelect extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: GradientAppBar(
title: Text('MultiSelect'),
),
body: MultipleSelectItems(),
);
}
}
class MultipleSelectItems extends StatefulWidget {
#override
_MultipleSelectItemsState createState() => _MultipleSelectItemsState();
}
class _MultipleSelectItemsState extends State<MultipleSelectItems> {
String selected = "First";
#override
Widget build(BuildContext context) {
return Container(
child: GestureDetector(
child: Column(
children: <Widget>[
SizedBox(
height: 40,
),
GestureDetector(
onTap: () {
setState(() {
selected = "First";
});
},
child: Container(
margin: EdgeInsets.only(left: 15, right: 15),
height:100,
width: double.maxFinite,
decoration: BoxDecoration(
color: selected == 'First' ? Colors.redAccent : Colors.lightBlueAccent,
),
child: ListTile(
title: Text(
'First',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 20,
fontFamily: 'WorksSansSemiBold',
fontWeight: FontWeight.bold,
),
),
),
),
),
Padding(padding: EdgeInsets.only(top: 20)),
GestureDetector(
onTap: () {
setState(() {
selected = "Second";
});
},
child: Container(
margin: EdgeInsets.only(left: 15, right: 15),
height:100,
width: double.maxFinite,
decoration: BoxDecoration(
color: selected == 'Second' ? Colors.redAccent : Colors.lightBlueAccent,
),
child: ListTile(
title: Text(
'Second',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 20,
fontFamily: 'WorksSansSemiBold',
fontWeight: FontWeight.bold,
),
),
),
),
),
Padding(padding: EdgeInsets.only(top: 20)),
GestureDetector(
onTap: () {
setState(() {
selected = "Third";
});
},
child: Container(
margin: EdgeInsets.only(left: 15, right: 15),
height:100,
width: double.maxFinite,
decoration: BoxDecoration(
color: selected == 'Third' ? Colors.redAccent : Colors.lightBlueAccent,
),
child: ListTile(
title: Text(
'Third',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 20,
fontFamily: 'WorksSansSemiBold',
fontWeight: FontWeight.bold,
),
),
),
),
),
SizedBox(
height: 40,
),
MaterialButton(
child: Text("Submit"),
color: Colors.blueGrey,
textColor: Colors.white,
onPressed: () {},
),
],
),
),
);
}
}
I am taking the requirement as you don't want to toggle, but to select multiple items. This is the solution.
In Flutter, creating a different StatefulWidget for the buttons, will be unique for every button, and when you select the buttons. And hitting each button will have unique informations only. I know it is little confusing but follow this, and you will understand.
class MultipleSelectItems extends StatefulWidget {
#override
_MultipleSelectItemsState createState() => _MultipleSelectItemsState();
}
class _MultipleSelectItemsState extends State<MultipleSelectItems> {
// This is responsible to crate your buttons
// Every button is created will be having it's unique instance only
// Means, if you hit one button, it won't effect another, and you can select
// multiple
// And you don't have to declare your buttons multiple times in the code
// Which is indeed bad way of coding :)
List<Widget> get listTileWidgets{
List<Widget> _widget = [SizedBox(height: 40.0)];
List<String> _buttonName = ['First', 'Second', 'Third', 'Fourth'];
// ListTileWidget is defined below in another StatefulWidget
_buttonName.forEach((name){
_widget.add(ListTileWidget(name: name));
_widget.add(SizedBox(height: 20.0));
});
return _widget;
}
#override
Widget build(BuildContext context) {
return Material(
child: Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: this.listTileWidgets
)
)
);
}
}
// This will accept name of the button which will be used to be given
// plus maintaining the uniqueness
class ListTileWidget extends StatefulWidget{
final String name;
ListTileWidget({Key key, this.name}):super(key:key);
#override
ListTileWidgetState createState() => ListTileWidgetState();
}
class ListTileWidgetState extends State<ListTileWidget>{
bool isTapped = false;
#override
Widget build(BuildContext context){
return GestureDetector(
onTap: () {
setState(() => isTapped = true);
},
child: Container(
margin: EdgeInsets.only(left: 15, right: 15),
height:100,
color: isTapped ? Colors.redAccent : Colors.lightBlueAccent,
width: double.maxFinite,
child: ListTile(
title: Text(
widget.name,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 20,
fontFamily: 'WorksSansSemiBold',
fontWeight: FontWeight.bold,
)
)
)
)
);
}
}
Result you will get is below:
I am sorry that, I have not added your "Submit" button. So in order to make that thing visible in your code, simply add this in your Column only, and you will be good to go:
Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
this.listTileWidgets,
SizedBox(height: 40),
MaterialButton(
child: Text("Submit"),
color: Colors.blueGrey,
textColor: Colors.white,
onPressed: () {},
)
]
)
That's pretty much it now.
I've got your answer. Changing the string variable to be an array can complete what you are looking to do. Then by checking if "First" or "Second" or "Third" is in the array we can determine what color the ListTile should be. Also when the ListTile is tapped we need to check if the array contains that string to determine if we are going to remove the string from the array (aka turning the color to blue) or if we need to add the string to the array (aka turning the color to red). Below I have included all of those changes to your class. Hope this answer helps! Comment if you have any questions
class MultipleSelectItems extends StatefulWidget {
#override
_MultipleSelectItemsState createState() => _MultipleSelectItemsState();
}
class _MultipleSelectItemsState extends State<MultipleSelectItems> {
var theSelected = ["First"];
#override
Widget build(BuildContext context) {
return Material(
child: Container(
child: GestureDetector(
child: Column(
children: <Widget>[
SizedBox(
height: 40,
),
GestureDetector(
onTap: () {
setState(() {
if(theSelected.contains("First")) {
theSelected.remove("First");
}
else {
theSelected.add("First");
}
});
},
child: Container(
margin: EdgeInsets.only(left: 15, right: 15),
height: 100,
width: double.maxFinite,
decoration: BoxDecoration(
color: theSelected.contains('First') ? Colors.redAccent : Colors.lightBlueAccent,
),
child: ListTile(
title: Text(
'First',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 20,
fontFamily: 'WorksSansSemiBold',
fontWeight: FontWeight.bold,
),
),
),
),
),
Padding(padding: EdgeInsets.only(top: 20)),
GestureDetector(
onTap: () {
setState(() {
if(theSelected.contains("Second")) {
theSelected.remove("Second");
}
else {
theSelected.add("Second");
}
});
},
child: Container(
margin: EdgeInsets.only(left: 15, right: 15),
height:100,
width: double.maxFinite,
decoration: BoxDecoration(
color: theSelected.contains('Second') ? Colors.redAccent : Colors.lightBlueAccent,
),
child: ListTile(
title: Text(
'Second',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 20,
fontFamily: 'WorksSansSemiBold',
fontWeight: FontWeight.bold,
),
),
),
),
),
Padding(padding: EdgeInsets.only(top: 20)),
GestureDetector(
onTap: () {
setState(() {
if(theSelected.contains("Third")) {
theSelected.remove("Third");
}
else {
theSelected.add("Third");
}
});
},
child: Container(
margin: EdgeInsets.only(left: 15, right: 15),
height:100,
width: double.maxFinite,
decoration: BoxDecoration(
color: theSelected.contains("Third") ? Colors.redAccent : Colors.lightBlueAccent,
),
child: ListTile(
title: Text(
'Third',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 20,
fontFamily: 'WorksSansSemiBold',
fontWeight: FontWeight.bold,
),
),
),
),
),
SizedBox(
height: 40,
),
MaterialButton(
child: Text("Submit"),
color: Colors.blueGrey,
textColor: Colors.white,
onPressed: () {},
),
],
),
),
),
);
}
}

trying to add to bag and to update prices and cups

I am trying to do this test TODOs: but i have been have issuses pls help: i am trying to Uncomment the _confirmOrderModalBottomSheet() method to show summary of order, Uncomment the setState() function to clear the price and cups, and Change the 'price' to 0 when this button is clicked Increment the _cupsCounter when 'Add to Bag' button is clicked, and to Call setState((){}) method to update both price and cups counter when 'Add to Bag' button is clicked
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Coffee Test',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primaryColor: Colors.white,
),
home: MyHomePage(title: 'Coffee Test'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _selectedPosition = -1;
String _coffeePrice ="0";
int _cupsCounter =0;
int price = 0;
String _currency ="₦";
static const String coffeeCup ="images/coffee_cup_size.png";
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
elevation: 0,
title: FlatButton(
onPressed: (){
//TODO: Uncomment the _confirmOrderModalBottomSheet() method to show summary of order
//_confirmOrderModalBottomSheet(totalPrice: "$_currency$price", numOfCups: "x $_cupsCounter");
},
child: Text("Buy Now",style: TextStyle(color: Colors.black87),),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(18.0), side: BorderSide(color: Colors.blue))
),
actions: [
InkWell(
onTap: () {
//TODO: Uncomment the setState() function to clear the price and cups
//TODO: Change the 'price' to 0 when this button is clicked
setState(() {
this.price = -1;
this._cupsCounter = 0;
});
Icon(Icons.clear);
}),
SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Container(
height: double.maxFinite,
alignment: Alignment.center,
child: Text("$_cupsCounter Cups = $_currency$price.00", style: TextStyle(fontSize: 18),),
),
)
],
),
body: Padding(padding: EdgeInsets.all(20), child: _mainBody(),) // This trailing comma makes auto-formatting nicer for build methods.
);
}
Widget _mainBody(){
return SingleChildScrollView(
child: Container(
height: double.maxFinite,
width: double.maxFinite,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Expanded(
flex: 0,
child: Stack(
children: [
Container(
width: double.maxFinite,
height: 250,
margin: EdgeInsets.only(left: 50, right: 50, bottom: 50, top: 60),
decoration: BoxDecoration(borderRadius:
BorderRadius.all(Radius.circular(180)),
color: Color.fromRGBO(239, 235, 233, 100)),
),
Container(
alignment: Alignment.center,
width: double.maxFinite,
height: 350,
child: Image.asset("images/cup_of_coffee.png", height: 300,),
)
],
)),
Padding(padding: EdgeInsets.all(10),),
Expanded(flex: 0,child: Text("Caffè Americano",
style: TextStyle(fontWeight: FontWeight.bold,
fontSize: 30),)),
Padding(padding: EdgeInsets.all(6),),
Expanded(flex: 0, child: Text("Select the cup size you want and we will deliver it to you in less than 48hours",
style: TextStyle(fontWeight: FontWeight.bold,
fontSize: 14, color: Colors.black45,),
textAlign: TextAlign.start,),
),
Container(
margin: EdgeInsets.only(top: 30, left: 20),
height: 55,
width: double.maxFinite,
alignment: Alignment.center,
child:Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
RichText(text: TextSpan(
text: _currency,
style: TextStyle(fontWeight: FontWeight.bold,
fontSize: 25, color: Colors.black87),
children: [
TextSpan(text: _coffeePrice, style: TextStyle(fontSize: 50, fontWeight: FontWeight.bold))
]
),),
Padding(
padding: EdgeInsets.only(right: 15),
),
ListView.builder(itemBuilder: (context, index){
return InkWell(
child: _coffeeSizeButton(_selectedPosition == index,
index ==0? "S" : index ==1? "M": "L"),
onTap: (){
setState(() {
this._coffeePrice= index ==0? "300" : index ==1? "600": "900";
_selectedPosition = index;
});
},
);
}, scrollDirection: Axis.horizontal,
itemCount: 3, shrinkWrap: true,),
],),
),
Container(
margin: EdgeInsets.only(top: 30),
padding: EdgeInsets.all(10),
width: double.maxFinite,
height: 70,
child: FlatButton(onPressed: (){
//TODO: Currently _cupsCounter only show 1 when this button is clicked.
// TODO: Increment the _cupsCounter when 'Add to Bag' button is clicked'
//TODO: Call setState((){}) method to update both price and cups counter when 'Add to Bag' button is clicked
this._cupsCounter = 1;
this.price += int.parse(_coffeePrice);
}, child: Center(child: Text("Add to Bag",
style: TextStyle(fontWeight: FontWeight.bold, color: Colors.white),)
,),
color: Colors.blue,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(50)
),
),
)
],
),
),
);
}
Widget _coffeeSizeButton(bool isSelected, String coffeeSize){
return Stack(
children: [
Container(alignment: Alignment.center, width: 55,
child: Text(coffeeSize, style: TextStyle(fontSize: 10, fontWeight: FontWeight.bold,
color: isSelected? Colors.blue: Colors.black45),),),
new Container(
margin: EdgeInsets.only(right: 10),
child: Image.asset(coffeeCup, width:50, color: isSelected ? Colors.blue: Colors.black45,),
decoration: BoxDecoration(border: Border(top: BorderSide(color: isSelected? Colors.blue: Colors.black45,
width: isSelected? 2: 1), left: BorderSide(color: isSelected? Colors.blue: Colors.black45,
width: isSelected? 2: 1), bottom: BorderSide(color: isSelected? Colors.blue: Colors.black45,
width: isSelected? 2: 1), right: BorderSide(color: isSelected ?Colors.blue: Colors.black45 ,
width: isSelected? 2: 1)), borderRadius: BorderRadius.all(Radius.circular(5))),
)
],
);
}
void _confirmOrderModalBottomSheet({String totalPrice, String numOfCups}){
showModalBottomSheet(
context: context,
builder: (builder){
return new Container(
height: 150.0,
color: Colors.transparent, //could change this to Color(0xFF737373),
//so you don't have to change MaterialApp canvasColor
child: new Container(
padding: EdgeInsets.all(10),
decoration: new BoxDecoration(
color: Colors.white,
borderRadius: new BorderRadius.only(
topLeft: const Radius.circular(10.0),
topRight: const Radius.circular(10.0))),
child: Column(
children: [
Container(
child: Text("Confirm Order",
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 18),),
alignment: Alignment.center, height: 30, decoration: BoxDecoration(
), ),
_getEstimate(totalPrice, numOfCups)
],
)),
);
}
);
}
Widget _getEstimate(String totalPrice, String numOfCups){
return Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Image.asset("images/cup_of_coffee.png", height: 70, width: 50,),
Padding(padding: EdgeInsets.all(10)),
Text(numOfCups, style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),),
Padding(padding: EdgeInsets.all(10)),
Text(totalPrice, style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),)
],
);
}
}
You're setting 1 to your _cupsCounter instead of adding one to it.
When updating your values, putting the operation i.e _cupsCounter += 1; in setState will update the state of your widget which makes values change in your widgets.
setState((){
_cupsCounter += 1; // make it +=1 instead of =1.
price += int.parse(_coffeePrice);
});
Also you can use setState by putting it after your operation which will update the state of your widget after the operation is done.
_cupsCounter += 1; // make it +=1 instead of =1.
price += int.parse(_coffeePrice);
setState((){});
Full code should look like this.
Container(
margin: EdgeInsets.only(top: 30),
padding: EdgeInsets.all(10),
width: double.maxFinite,
height: 70,
child: FlatButton(onPressed: (){
// Currently _cupsCounter only show 1 when this button is clicked.
// Increment the _cupsCounter when 'Add to Bag' button is clicked'
// Call setState((){}) method to update both price and cups counter when 'Add to Bag' button is clicked
setState((){
_cupsCounter += 1; // make it +=1 instead of =1.
price += int.parse(_coffeePrice);
}); // call setState like this
}, child: Center(child: Text("Add to Bag",
style: TextStyle(fontWeight: FontWeight.bold, color: Colors.white),)
,),
color: Colors.blue,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(50)
),
),
)