Change state from another widget in flutter? - 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();

Related

How do i correctly position these items horizontally in flutter to avoid overflow?

I have a list of items that are responsible for a tab bar design, i want to make all the sizedboxes display at a go and not overflow horizontally.
I will give my code for better clarification.
This is what i could come up with after over an hour of tussle:
And this is what i am expecting
I will give my code snippets of the view below.
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:google_fonts/google_fonts.dart';
class JobsHeaderWidget extends StatefulWidget {
const JobsHeaderWidget({
Key key,
}) : super(key: key);
#override
State<JobsHeaderWidget> createState() => _JobsHeaderWidgetState();
}
class _JobsHeaderWidgetState extends State<JobsHeaderWidget> {
List<String> items = [
"All",
"Critical",
"Open",
"Closed",
"Overdue",
];
int current = 0;
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(left: 10.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Jobs',
style: GoogleFonts.poppins(
color: Colors.black, fontSize: 18, fontWeight: FontWeight.w600),
),
Row(
children: [
Text(
'View Insights ',
style: GoogleFonts.poppins(
color: Color(0xff3498DB),
fontSize: 12,
fontWeight: FontWeight.w500),
),
Icon(
Icons.arrow_forward_ios,
color: Color(0xff3498DB),
size: 12,
),
],
),
filterJobs()
],
),
);
}
Widget filterJobs() {
return Container(
width: double.infinity,
child: Column(
children: [
/// CUSTOM TABBAR
SizedBox(
width: double.infinity,
height: 60,
child: ListView.builder(
physics: const BouncingScrollPhysics(),
itemCount: items.length,
scrollDirection: Axis.horizontal,
itemBuilder: (ctx, index) {
return Column(
children: [
GestureDetector(
onTap: () {
setState(() {
current = index;
});
},
child: AnimatedContainer(
duration: const Duration(milliseconds: 300),
margin: const EdgeInsets.all(5),
decoration: BoxDecoration(
color: current == index
? Color(0xff34495E)
: Color(0xffF5F5F5),
borderRadius: BorderRadius.circular(11),
),
child: Center(
child: Padding(
padding: const EdgeInsets.only(
left: 10.0, right: 10.0, top: 5, bottom: 5),
child: Text(
items[index],
style: GoogleFonts.poppins(
fontSize: 10,
fontWeight: FontWeight.w500,
color: current == index
? Colors.white
: Colors.grey),
),
),
),
),
),
],
);
}),
),
// Builder(
// builder: (context) {
// switch (current) {
// case 0:
// return AllNotificationItemsView();
// case 1:
// return JobsNotificationItemsView();
// case 2:
// return MessagesNotificationItemsView();
// case 3:
// return CustomersNotificationItemsView();
// default:
// return SizedBox.shrink();
// }
// },
// )
],
),
);
}
}
The reason for overflow is List View Builder. Remove it and add a Row widget instead. Iterate the list item in it and you will get your desired output.
Full Code : -
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Image',
theme: ThemeData(
primarySwatch: Colors.blue,
),
debugShowCheckedModeBanner: false,
home: const JobsHeaderWidget(),
);
}
}
class JobsHeaderWidget extends StatefulWidget {
const JobsHeaderWidget({super.key});
#override
State<JobsHeaderWidget> createState() => _JobsHeaderWidgetState();
}
class _JobsHeaderWidgetState extends State<JobsHeaderWidget> {
List<String> items = [
"All",
"Critical",
"Open",
"Closed",
"Overdue",
];
int current = 0;
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey,
body: Padding(
padding: const EdgeInsets.only(left: 10.0, right: 10, top: 5),
child: Align(
alignment: Alignment.topCenter,
child: Container(
constraints: const BoxConstraints(maxWidth: 610, maxHeight: 100),
alignment: Alignment.center,
width: double.infinity,
child: IntrinsicWidth(
child: FittedBox(
fit: BoxFit.fitWidth,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
for (int i = 0; i < items.length; i++) ...[
GestureDetector(
onTap: () {
setState(() {
current = i;
});
},
child: AnimatedContainer(
height: 40,
duration: const Duration(milliseconds: 300),
margin: const EdgeInsets.all(5),
padding: const EdgeInsets.only(
left: 15.0, right: 15.0, top: 5, bottom: 5),
decoration: BoxDecoration(
color: current == i
? const Color(0xff34495E)
: const Color(0xffF5F5F5),
borderRadius: BorderRadius.circular(11),
),
child: Center(
child: Text(
items[i],
style: GoogleFonts.poppins(
fontSize: 19,
fontWeight: FontWeight.w500,
color: current == i
? Colors.white
: Colors.grey),
),
),
),
),
]
],
),
),
),
),
),
),
);
}
}
Output : -
Hey there for making the appbar not overflowing, you must use expanded widget. try to wrap your gestureDetector or whatever widget that you create for making the design for each listview child like this
Expanded(
child: GestureDetector(
onTap: () {
setState(() {
current = i;
});
},
child: AnimatedContainer(
height: 40,
duration: const Duration(milliseconds: 300),
margin: const EdgeInsets.all(5),
padding: const EdgeInsets.only(
left: 15.0, right: 15.0, top: 5, bottom: 5),
decoration: BoxDecoration(
color: current == i
? const Color(0xff34495E)
: const Color(0xffF5F5F5),
borderRadius: BorderRadius.circular(11),
),
child: Center(
child: Text(
items[i],
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w500,
color: current == i ? Colors.white : Colors.grey),
),
),
),
),
),
as you can see when you doing this the design will look like this
the text inside of the design would gone because of overflowing issue, you can change the text widget into this widget https://pub.dev/packages/auto_size_text
this is the snipet
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey,
body: SafeArea(
child: Padding(
padding: const EdgeInsets.only(left: 5.0, right: 5, top: 20),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
for (int i = 0; i < items.length; i++) ...[
Expanded(
child: GestureDetector(
onTap: () {
setState(() {
current = i;
});
},
child: AnimatedContainer(
height: 40,
duration: const Duration(milliseconds: 300),
margin: const EdgeInsets.all(5),
padding: const EdgeInsets.only(
left: 5.0, right: 5.0, top: 5, bottom: 5),
decoration: BoxDecoration(
color: current == i
? const Color(0xff34495E)
: const Color(0xffF5F5F5),
borderRadius: BorderRadius.circular(11),
),
child: Center(
child: AutoSizeText(
items[i],
maxLines: 1,
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w500,
color:
current == i ? Colors.white : Colors.grey),
),
),
),
),
),
]
],
),
),
));
but surely the text would be some of big and some of small look like this, and this is the result

Flutter OnTap Listview item

I'm new to flutter, may I know how to get different outputs when I click on each item? I have total of 3 lists, for each item, I want to get their respective output and now I only can get the same outputs for each item. How to get different outputs when I click on it? Thanks all.
this is my ListView coding :
class _CatState extends State<Cat> {
List<String> categories = ["Furniture", "Lighting", "Decoration"];
int selectedIndex = 0;
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 5.0),
child: SizedBox(
height: 25,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: categories.length,
itemBuilder: (context, index) => buildCategory(index),
),
));
}
Widget buildCategory(int index) {
return GestureDetector(
onTap: () {
setState(() {
selectedIndex = index;
});
},
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 40.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
categories[index],
style: TextStyle(
fontSize: 15,
color: selectedIndex == index ? Colors.black : Colors.black45,
),
),
Container(
margin: EdgeInsets.only(top: DefaultPadding / 4), //top padding
height: 2,
width: 50,
color: selectedIndex == index
? Colors.blueAccent[200]
: Colors.transparent,
)
],
When onTap the item:
class ItemCard extends StatelessWidget {
final Product product;
final Decor decoration;
final Light light;
final Function press;
const ItemCard({
Key key,
this.press,
this.product,
this.decoration,
this.light,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: press,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
child: Container(
padding: EdgeInsets.all(2.0),
// height: 180,
// width: 160,
child: ClipRRect(
borderRadius: BorderRadius.circular(25.0),
child: Image.asset(
product.img, // products image
)),
),
),
Padding(
padding: const EdgeInsets.symmetric(vertical: DefaultPadding / 4),
child: Text(
product.name, // products name
textAlign: TextAlign.center,
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 18,
),
),
),
Text(
product.price,
textAlign: TextAlign.center,
style: TextStyle(fontStyle: FontStyle.italic),
)
],
),
Use switch case if it is static. For example on itemBuilder in Gridview:
ItemCard(
product:furniture[index],
press: _onPressed(index),
)
and in onPressed method, do whatever you want:
_onPressed(int index){
switch(index):
case 0:
your code:
break;
case 1:
//code
}
so by this you can make different onTap function

Widget not redrawing despite Setstate & UniqueKey

I have this code for selecting options in a product page.
The index is updating well, but the color of the selected option refuses to change (as well as the name of the selected option on the right -- see the image below), and i can't figure why..
I have tried to use Setstate(), and to use unique keys for the related parent widgets
Here the image:
import 'package:animate_do/animate_do.dart';
import 'package:flutter/material.dart';
import 'package:prem_market/models/product.dart';
import 'package:prem_market/models/product_variation.dart';
class DisplayAttributes extends StatefulWidget {
const DisplayAttributes({
Key key,
this.data,
Function onChanged,
}) : super(key: key);
final Product data;
#override
_DisplayAttributesState createState() => _DisplayAttributesState();
}
class _DisplayAttributesState extends State<DisplayAttributes> {
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
int activeOption = 0;
return Column(
children: [
...List.generate(
this.widget.data.attributes.length,
(index) => !this.widget.data.attributes[index].variation
? SizedBox()
: Column(
children: <Widget>[
SizedBox(
height: 25,
),
Padding(
padding: EdgeInsets.only(left: 25, right: 25),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
FadeInDown(
delay: Duration(milliseconds: 450),
child: Text(
this.widget.data.attributes[index].name,
style: TextStyle(
fontSize: 16, fontWeight: FontWeight.w600),
),
),
FadeInDown(
delay: Duration(milliseconds: 450),
child: Text(
activeOption == 100
? '-'
: this
.widget
.data
.attributes[index]
.options[activeOption],
style: TextStyle(
fontSize: 16,
//color: black.withOpacity(0.7)
),
),
)
],
)),
SizedBox(
height: 25,
),
FadeInDown(
delay: Duration(milliseconds: 500),
child: Padding(
padding: EdgeInsets.only(left: 20, right: 25),
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
children: this
.widget
.data
.attributes[index]
.options
.asMap()
.map<int, GestureDetector>(
(i, String childData) {
return MapEntry(
i,
GestureDetector(
key: UniqueKey(),
onTap: () {
setState(() {
if (activeOption == i) {
//selected = false;
activeOption = 100;
} else {
activeOption = i;
//selected = true;
}
});
FocusScope.of(context)
.requestFocus(new FocusNode());
},
child: Padding(
padding: const EdgeInsets.only(
right: 15,
bottom: 5,
left: 5,
top: 5),
child: Container(
key: UniqueKey(),
//width: 50,
height: 50,
padding: EdgeInsets.symmetric(
horizontal: 10),
decoration: BoxDecoration(
color: activeOption == i
? Theme.of(context)
.textTheme
.headline6
.color
: Colors.grey[200],
borderRadius:
BorderRadius.circular(8),
boxShadow: [
BoxShadow(
spreadRadius: 0.5,
blurRadius: 1,
color: Theme.of(context)
.shadowColor
.withOpacity(0.1))
]),
child: Center(
child: Text(
childData,
key: UniqueKey(),
style: TextStyle(
fontSize: 16,
color: activeOption == i
? Theme.of(context)
.backgroundColor
: Theme.of(context)
.shadowColor),
),
),
),
),
));
})
.values
.toList(),
),
),
),
),
],
),
),
],
);
}
}
You are resetting activeOption to 0 in build function make it a global variable. Everytime you call setState() build method is called which again resets it to 0
#override
Widget build(BuildContext context) {
int activeOption = 0;
to
int activeOption = 0;
#override
Widget build(BuildContext context) {

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 .

CustomScrollView object does not update with input from StatefulBuilder

I have a CustomScrollView that gets updated upon user input. The actual items in the ListView are in a SliverChildBuilderDelegate inside the CustomScrollView which is inside the body of the Scaffold object (see the code below). If a user adds an item in the form that is inside the StatefulBuilder which is inside a showDialog object, the item does not get added to the planets list which thus does not update the ListView. I think the problem is caused by the StatefulBuilder which I need to update my DropdownButton.
My code:
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
void main() {
runApp(MaterialApp(
home: HomePage(),
));
}
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class Planet {
final String id;
final String name;
final String location;
final String distance;
final String gravity;
final String image;
const Planet({this.id, this.name, this.location, this.distance, this.gravity, this.image});
}
class Coin {
int id;
String name;
Coin(this.id, this.name);
static List<Coin> getCoins() {
return <Coin>[
Coin(1, 'coin1'),
Coin(2, 'coin2'),
Coin(3, 'coin3'),
Coin(4, 'coin4'),
Coin(5, 'coin5'),
];
}
}
class MenuItem {
String title;
String icon;
Color color;
Function func;
MenuItem(this.title, this.icon, this.color, this.func);
}
class _HomePageState extends State<HomePage> {
List<Coin> _coins = Coin.getCoins();
List<DropdownMenuItem<Coin>> _dropdownMenuItems;
Coin _selectedCoin;
#override
void initState() {
_dropdownMenuItems = buildDropdownMenuItems(_coins);
_selectedCoin = _dropdownMenuItems[0].value;
super.initState();
_menuItems = createMenuItems();
_selectedMenuItem = _menuItems.first;
}
MenuItem _selectedMenuItem;
List<MenuItem> _menuItems;
List<Widget> _menuOptionWidgets = [];
List<MenuItem> createMenuItems() {
final menuItems = [
new MenuItem("Dashboard", 'assets/images/dashboard.png', Colors.black, () => new Dashboard()),
new MenuItem("Cows", 'assets/images/cow.png', Colors.green, () => new Cows()),
];
return menuItems;
}
_onSelectItem(MenuItem menuItem) {
setState(() {
_selectedMenuItem = menuItem;
});
Navigator.push(
context,
MaterialPageRoute(builder: (context) => HomePage()),
);
Navigator.of(context).pop(); // close side menu
}
List<DropdownMenuItem<Coin>> buildDropdownMenuItems(List coins) {
List<DropdownMenuItem<Coin>> items = List();
for (Coin coin in coins) {
items.add(
DropdownMenuItem(
value: coin,
child:
Text(
coin.name,
style: TextStyle(
fontSize: 18.0,
color: Colors.black87,
fontWeight: FontWeight.bold
),
),
),
);
}
return items;
}
onChangeDropdownItem(Coin selectedCoin, StateSetter setState) {
setState(() {
_selectedCoin = selectedCoin;
print('${_selectedCoin.name}');
});
}
final coinController = TextEditingController();
final amountController = TextEditingController();
final purposeController = TextEditingController();
#override
void dispose() {
// Clean up the controller when the widget is disposed.
coinController.dispose();
amountController.dispose();
purposeController.dispose();
super.dispose();
}
List<Planet> planets = [];
#override
Widget build(BuildContext context) {
_menuOptionWidgets = [];
DateTime now = DateTime.now();
String formattedDate = DateFormat('yyyy-MM-dd kk:mm').format(now);
for (var menuItem in _menuItems) {
_menuOptionWidgets.add(new Container(
decoration: new BoxDecoration(
color: menuItem == _selectedMenuItem
? Colors.grey[200]
: Colors.white),
child: new ListTile(
leading: new Image.asset(menuItem.icon),
onTap: () => _onSelectItem(menuItem),
title: Text(
menuItem.title,
style: new TextStyle(
fontSize: 20.0,
color: menuItem.color,
fontWeight: menuItem == _selectedMenuItem
? FontWeight.bold
: FontWeight.w300),
))));
_menuOptionWidgets.add(
new SizedBox(
child: new Center(
child: new Container(
margin: new EdgeInsetsDirectional.only(start: 20.0, end: 20.0),
height: 0.3,
color: Colors.grey,
),
),
),
);
}
double screenHeight;
screenHeight = MediaQuery.of(context).size.height;
return Scaffold(
appBar: AppBar(
title: Text('Dashboard'),
backgroundColor: Color.fromRGBO(53, 73, 94, 0.9),
elevation: 0.0,
// leading: Container(),
),
drawer: new Drawer(
child: new ListView(
children: <Widget>[
new Container(
child: new ListTile(
leading: new CircleAvatar(
backgroundColor: Colors.black,
radius: 40.0,
child: Text(
"L",style: TextStyle(
color: Colors.orange,
fontSize: 46.0),
),
),
title: Text("Welcome",style: TextStyle(fontSize: 46.0),)
),
margin: new EdgeInsetsDirectional.only(top: 20.0),
color: Colors.white,
constraints: BoxConstraints(maxHeight: 90.0, minHeight: 90.0)),
new SizedBox(
child: new Center(
child: new Container(
margin:
new EdgeInsetsDirectional.only(start: 10.0, end: 10.0),
height: 0.3,
color: Colors.black,
),
),
),
new Container(
color: Colors.white,
child: new Column(children: _menuOptionWidgets),
),
],
),
),
floatingActionButton: new Container(
width: 120.0,
height: 120.0,
padding: const EdgeInsets.only(bottom:40.0),
child: FloatingActionButton(
child: Icon(Icons.add,size: 50.0),
elevation: 0.0,
onPressed: () {
showDialog(
context: context,
builder: (context) {
return StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return Container(
margin: EdgeInsets.only(
top: screenHeight / 5,
bottom: screenHeight / 4
),
padding: EdgeInsets.only(left: 10, right: 10),
child: Card(
color: Color.fromRGBO(53, 73, 94, 0.9),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
elevation: 8,
child: Padding(
padding: const EdgeInsets.all(30.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Align(
alignment: Alignment.topCenter,
child: Text(
"Create",
style: Style.headerTextStyle
),
),
Divider(
color: Colors.white
),
SizedBox(
height: 15,
),
DropdownButton(
value: _selectedCoin,
items: _dropdownMenuItems,
onChanged: (selectedCoin) {
setState(() {
_selectedCoin = selectedCoin;
print('${_selectedCoin.name}');
});
}, //onChangeDropdownItem(_selectedCoin, setState),
),
SizedBox(
height: 15,
),
TextFormField(
decoration: InputDecoration(
labelText: "Amount",
hasFloatingPlaceholder: true,
labelStyle: Style.commonTextStyle
),
controller: amountController,
),
SizedBox(
height: 20,
),
TextFormField(
decoration: InputDecoration(
labelText: "What is it for?",
hasFloatingPlaceholder: true,
labelStyle: Style.commonTextStyle
),
controller: purposeController,
),
SizedBox(
height: 20,
),
Row(
mainAxisAlignment: MainAxisAlignment
.spaceEvenly,
children: <Widget>[
Expanded(
child: Container(),
),
ButtonTheme(
minWidth: 150.0,
child: RaisedButton(
padding: EdgeInsets.all(8.0),
child: Text('Share',
style: TextStyle(
fontSize: 24,
color: Colors.black87,
fontWeight: FontWeight.bold
),
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(
18.0)
),
color: Colors.white,
splashColor: Colors.blueGrey,
onPressed: () {
setState(() {
planets.add(Planet(
id: '1',
// TODO need to adjust this
name: purposeController.text,
location: '€' + amountController.text,
distance: formattedDate,
gravity: 'test',
image: _setImage(), // TODO might have to pass _selectedCoin as parameter
)
);
});
Navigator.pop(context);
},
),
),
],
),
],
),
),
),
);
}
);
},
);
},
),
),
body: Column(
children: <Widget>[
new Expanded(
child: new Container(
color: Color.fromRGBO(53, 73, 94, 0.9),
child: new CustomScrollView(
scrollDirection: Axis.vertical,
slivers: <Widget>[
new SliverPadding(
padding: const EdgeInsets.symmetric(vertical: 0.0),
sliver: new SliverFixedExtentList(
itemExtent: 152.0,
delegate: new SliverChildBuilderDelegate(
(context, index) => new PlanetRow(planets[index]),
childCount: planets.length,
),
),
),
],
),
),
),
],
),
);
}
}
The expected result is that the object from user input gets added to the planets list. The Sliver object then gets the updated planets list which shows the user input in a Planet Card. Any help will be greatly appreciated!