如何在用户添加数据并将其存储到列表视图时更新金额值 flutter
How to update the amount value when the user add data and store it to list view flutter
大家好,我是 Flutter 新手,需要您的帮助。在这种情况下,我可以添加预算并将其检索到列表视图。但现在我正在尝试为每个类别只显示 1 个列表,但计算数量?因此,如果用户添加新预算,金额将被计算并更新到列表视图(使用相同的货币)。如果用户在预算代码中添加预算,任何人都可以帮助我如何列出相同类别但更新金额?请帮忙。谢谢你。对于数据库,我在 firebase
中使用 Firestore
选择预算类别
import 'package:flutter/material.dart';
import 'package:monger_app/localization/localization_constants.dart';
import 'package:monger_app/page/detail.dart';
import 'package:monger_app/theme/colors.dart';
class BudgetSettings extends StatefulWidget {
@override
_BudgetSettingsState createState() => _BudgetSettingsState();
}
class _BudgetSettingsState extends State<BudgetSettings> {
List<Container> categorylist = new List();
var character=[
{"name":"Food", "image":"food.png"},
{"name":"Social-Life", "image":"travel.png"},
{"name":"Transportation", "image":"transportation.png"},
{"name":"Beauty", "image":"makeup.png"},
{"name":"Household", "image":"household.png"},
{"name":"Education", "image":"education.png"},
{"name":"Health", "image":"health.png"},
{"name":"Gift", "image":"gift.png"},
{"name":"Other", "image":"other.png"},
];
_makelist() async {
for (var i = 0; i < character.length; i++) {
final newcharacter = character[i];
final String image = newcharacter["image"];
categorylist.add(
new Container(
padding: new EdgeInsets.all(20.0),
child: new Card( child:
SingleChildScrollView(
child: new Column(
children: <Widget>[
new Hero(
tag: newcharacter['name'],
child: new Material(
child: new InkWell(
onTap: ()=> Navigator.of(context).push(new MaterialPageRoute(
builder: (BuildContext context)=> new Detail(name: newcharacter['name'], image: image,),
)),
child:
new Image.asset("assets/$image", fit: BoxFit.contain,),
)
),
),
//new Image.asset('assets/$image', fit: BoxFit.cover,),
new Padding(padding: new EdgeInsets.all(5.0),),
new Text(newcharacter['name'], style: new TextStyle(fontSize: 18.0),),
],
),
),
),
),
);
}
}
@override
void initState() {
_makelist();
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: primary,
title: Text(getTranslated((context), "budget_settings"),
),),
body: new GridView.count(
crossAxisCount: 2,
children: categorylist,
),
);
}
}
添加预算代码
import 'package:dropdownfield/dropdownfield.dart';
import 'package:flutter/material.dart';
import 'package:monger_app/localization/localization_constants.dart';
import 'package:monger_app/page/account.dart';
import 'package:monger_app/page/budgetsettings.dart';
import 'package:monger_app/theme/colors.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
class Detail extends StatefulWidget {
Detail({this.name, this.image});
final String name;
final String image;
@override
_DetailState createState() => _DetailState();
}
class _DetailState extends State<Detail> {
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: AppBar(
title: Text(getTranslated((context), "budget_settings"),),
elevation: 0,
brightness: Brightness.light,
backgroundColor: primary,
leading: IconButton(
onPressed: (){
Navigator.pop(context, MaterialPageRoute(builder: (context) => Account()));
},
icon: Icon(Icons.arrow_back_ios,
size: 20,
color: Colors.black,),
),
),
body: new ListView(
children: <Widget>[
new Container(
height: 250.0,
child:
new Hero(tag: widget.name,
child: new Material(
child: new InkWell(
child: new Image.asset("assets/${widget.image}", fit: BoxFit.contain,),
)
))
),
new Name(name: widget.name,),
],
),
);
}
}
class Name extends StatefulWidget {
Name({this.name});
final String name;
@override
_NameState createState() => _NameState();
}
class _NameState extends State<Name> {
@override
String selectCurrency;
final currencySelected = TextEditingController();
var _formKey = GlobalKey<FormState>();
List <String> currencycategories = [
"IDR",
"MYR",
"USD",
"CNY"
];
Widget build(BuildContext context) {
final amount = TextEditingController();
FirebaseFirestore firestore = FirebaseFirestore.instance;
CollectionReference collect= firestore.collection("Budget");
final FirebaseAuth _auth = FirebaseAuth.instance;
final User user =_auth.currentUser;
final uid = user.uid;
return Form(
key: _formKey,
child: Padding(
padding: EdgeInsets.all(20.0),
child: Column(
children: <Widget>[
Container(
child: Center(
child: Column(
children: <Widget>[
Padding(
padding: EdgeInsets.all(20.0),
child: Text(
widget.name,
textAlign: TextAlign.center,
style: new TextStyle(
fontSize: 25.0,
color: primary,
fontWeight: FontWeight.bold,
),
),
),
Row(
children: <Widget> [
new Expanded(child: new DropDownField(
controller: currencySelected,
labelText: getTranslated((context), "currency_hint"),
enabled: true,
itemsVisibleInDropdown: 4,
items: currencycategories,
onValueChanged: (dynamic value) {
selectCurrency = value;
},
value: selectCurrency,
required: false,
),
flex: 2,
),
new SizedBox(
width: 10.0,
),
new Expanded(child: TextFormField(
validator: (input) {
if (input.isEmpty) return 'Please fill up the text fields';
},
controller: amount,
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: getTranslated((context), "budget_enter"),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: secondary),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: secondary),
),
),
),
flex: 2,
)],
),
Padding(
padding: EdgeInsets.all(20.0),
child: ElevatedButton(
onPressed: () async {
final FirebaseAuth _auth = FirebaseAuth
.instance;
final User user = _auth.currentUser;
final uid = user.uid;
if(!_formKey.currentState.validate()){
return;
}
_formKey.currentState.save();
collect.add({
'name': this.widget.name,
'currency': selectCurrency,
'amount': amount.text,
});
amount.text = "";
Navigator.pop(context);
},
child: Text(getTranslated((context), "save_button").toUpperCase(), style: TextStyle (
fontSize: 14,
)),
style: ButtonStyle(
padding: MaterialStateProperty.all<EdgeInsets>(EdgeInsets.all(20.0)),
foregroundColor: MaterialStateProperty.all<Color>(Colors.white),
backgroundColor: MaterialStateProperty.all<Color>(Colors.pink),
shape: MaterialStateProperty.all<RoundedRectangleBorder>(
RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
side: BorderSide(color: secondary)
),
),
),
),
)
],
),
)
)
],
),
)
);
}
}
检索到列表查看代码
import 'package:flutter/material.dart';
import 'package:monger_app/localization/localization_constants.dart';
import 'package:monger_app/page/transaction.dart';
import 'package:monger_app/theme/colors.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import './transaction.dart' as expense;
import './transaction.dart' as income;
class TransactionMonthly extends StatefulWidget {
@override
_TransactionMonthlyState createState() => _TransactionMonthlyState();
}
class _TransactionMonthlyState extends State<TransactionMonthly> with SingleTickerProviderStateMixin {
TabController controller;
@override
void initState() {
controller = new TabController(vsync: this, length: 2);
super.initState();
}
@override
void dispose() {
controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(getTranslated(context, 'budget_title'),),
elevation: 0,
brightness: Brightness.light,
backgroundColor: primary,
leading: IconButton(
onPressed: (){
Navigator.pop(context, MaterialPageRoute(builder: (context) => Transactions()));
},
icon: Icon(Icons.arrow_back_ios,
size: 20,
color: Colors.black,),
),
),
body: StreamBuilder(
stream: FirebaseFirestore.instance.collection('Budget').snapshots(),
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.hasData) {
return ListView(
children: snapshot.data.docs.map((document) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(children: [
SizedBox(width: 10,),
Text(document.get('name'),style: TextStyle(fontSize: 16,
color: primary,
fontWeight: FontWeight.w600
),),
],
),
SizedBox(height: 10,),
Row(children: [
SizedBox(width: 10,),
Text(document.get('currency'),style: TextStyle(fontSize: 16,
color: primary,
fontWeight: FontWeight.w600
),),
SizedBox(width: 10,),
Text(document.get('amount'),style: TextStyle(fontSize: 16,
color: primary,
fontWeight: FontWeight.w600
),),
],
),
SizedBox(height: 8,),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
GestureDetector(
onTap: (){
Widget cancelButton = FlatButton(child: Text("Cancel"),
onPressed: (){
Navigator.pop(context);
},
);
Widget deleteButton = FlatButton(child: Text("Delete"),
onPressed: (){
FirebaseFirestore.instance.collection('Budget').doc(document.id).delete();
Navigator.pop(context);
},
);
showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text('Delete Budget'),
content: Text('Are you sure want to delete it?'),
actions: [
cancelButton,
deleteButton,
],
),
);
//_showDeleteDialog();
//_showDeleteDialog(document: document);
},
child: Row(
children: [
Icon(Icons.delete_forever_outlined,
color: Colors.red,
),
SizedBox(width: 6,),
Text('Delete', style: TextStyle(fontSize: 16,
color: Colors.red,
fontWeight: FontWeight.w600
), ),
],
),
)
],
)
],)
);
}).toList(),
);
}
return Center(
child: CircularProgressIndicator(),
);
}
),
);
}
}
我想你想要的是一种按名称分组,这样你就可以在你的例子中用 160 来显示食物类别,而不是同一类别的两倍(如果我错了请纠正我)。我的建议是首先创建一个名为 Budget
的 class 以及您的三个属性 name, currency and amount
。当您在 TransactionMonthly Streambuilder
中收到数据时,您需要按名称对快照数据进行分组。完成后,您将创建一个预算列表 List<Budget> budgets
,以便您添加每个预算名称的金额总和。
这里有一个示例代码,您可以简单地复制粘贴并在 DartPad 上自行试用:
import 'package:collection/collection.dart';
//DATA coming from your Firebase collection
Map<String, dynamic> data1 = {
'name':"Food",
'currency': "IDR",
'amount': 100,
};
Map<String, dynamic> data2 = {
'name':"Food",
'currency': "IDR",
'amount': 60,
};
Map<String, dynamic> data3 = {
'name':"Beauty",
'currency': "USD",
'amount': 120,
};
//Your Budget class
class Budget{
String currency;
String name;
int amount;
@override
String toString(){
return "Budget: {currency: $currency, name: $name, amount: $amount}";
}
Budget({required this.currency, required this.name, required this.amount});
}
void main(){
List<Map<String, dynamic>> snapshot = [data1, data2, data3];
List<Budget> budgets = [];
//you group your budgets by name so you will have: {'Food': [data1, data2], 'Beauty':[data3]}
final groupByName = groupBy(snapshot, (Map<String, dynamic> doc)=>doc['name']);
print(groupByName);
int totalAmount = 0;
String currency = "";
groupByName.forEach((name, value){
//because we grouped by name every value will have same currency
currency = value[0]['currency'];
//Here we calculate the sum of all Food
totalAmount = value.map((e)=>e['amount']).reduce((v, e)=> v+e);
budgets.add(Budget(currency: currency, amount: totalAmount, name: name));
});
//budgets is your final list to use in your listView
print(budgets);
}
大家好,我是 Flutter 新手,需要您的帮助。在这种情况下,我可以添加预算并将其检索到列表视图。但现在我正在尝试为每个类别只显示 1 个列表,但计算数量?因此,如果用户添加新预算,金额将被计算并更新到列表视图(使用相同的货币)。如果用户在预算代码中添加预算,任何人都可以帮助我如何列出相同类别但更新金额?请帮忙。谢谢你。对于数据库,我在 firebase
中使用 Firestore选择预算类别
import 'package:flutter/material.dart';
import 'package:monger_app/localization/localization_constants.dart';
import 'package:monger_app/page/detail.dart';
import 'package:monger_app/theme/colors.dart';
class BudgetSettings extends StatefulWidget {
@override
_BudgetSettingsState createState() => _BudgetSettingsState();
}
class _BudgetSettingsState extends State<BudgetSettings> {
List<Container> categorylist = new List();
var character=[
{"name":"Food", "image":"food.png"},
{"name":"Social-Life", "image":"travel.png"},
{"name":"Transportation", "image":"transportation.png"},
{"name":"Beauty", "image":"makeup.png"},
{"name":"Household", "image":"household.png"},
{"name":"Education", "image":"education.png"},
{"name":"Health", "image":"health.png"},
{"name":"Gift", "image":"gift.png"},
{"name":"Other", "image":"other.png"},
];
_makelist() async {
for (var i = 0; i < character.length; i++) {
final newcharacter = character[i];
final String image = newcharacter["image"];
categorylist.add(
new Container(
padding: new EdgeInsets.all(20.0),
child: new Card( child:
SingleChildScrollView(
child: new Column(
children: <Widget>[
new Hero(
tag: newcharacter['name'],
child: new Material(
child: new InkWell(
onTap: ()=> Navigator.of(context).push(new MaterialPageRoute(
builder: (BuildContext context)=> new Detail(name: newcharacter['name'], image: image,),
)),
child:
new Image.asset("assets/$image", fit: BoxFit.contain,),
)
),
),
//new Image.asset('assets/$image', fit: BoxFit.cover,),
new Padding(padding: new EdgeInsets.all(5.0),),
new Text(newcharacter['name'], style: new TextStyle(fontSize: 18.0),),
],
),
),
),
),
);
}
}
@override
void initState() {
_makelist();
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: primary,
title: Text(getTranslated((context), "budget_settings"),
),),
body: new GridView.count(
crossAxisCount: 2,
children: categorylist,
),
);
}
}
添加预算代码
import 'package:dropdownfield/dropdownfield.dart';
import 'package:flutter/material.dart';
import 'package:monger_app/localization/localization_constants.dart';
import 'package:monger_app/page/account.dart';
import 'package:monger_app/page/budgetsettings.dart';
import 'package:monger_app/theme/colors.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
class Detail extends StatefulWidget {
Detail({this.name, this.image});
final String name;
final String image;
@override
_DetailState createState() => _DetailState();
}
class _DetailState extends State<Detail> {
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: AppBar(
title: Text(getTranslated((context), "budget_settings"),),
elevation: 0,
brightness: Brightness.light,
backgroundColor: primary,
leading: IconButton(
onPressed: (){
Navigator.pop(context, MaterialPageRoute(builder: (context) => Account()));
},
icon: Icon(Icons.arrow_back_ios,
size: 20,
color: Colors.black,),
),
),
body: new ListView(
children: <Widget>[
new Container(
height: 250.0,
child:
new Hero(tag: widget.name,
child: new Material(
child: new InkWell(
child: new Image.asset("assets/${widget.image}", fit: BoxFit.contain,),
)
))
),
new Name(name: widget.name,),
],
),
);
}
}
class Name extends StatefulWidget {
Name({this.name});
final String name;
@override
_NameState createState() => _NameState();
}
class _NameState extends State<Name> {
@override
String selectCurrency;
final currencySelected = TextEditingController();
var _formKey = GlobalKey<FormState>();
List <String> currencycategories = [
"IDR",
"MYR",
"USD",
"CNY"
];
Widget build(BuildContext context) {
final amount = TextEditingController();
FirebaseFirestore firestore = FirebaseFirestore.instance;
CollectionReference collect= firestore.collection("Budget");
final FirebaseAuth _auth = FirebaseAuth.instance;
final User user =_auth.currentUser;
final uid = user.uid;
return Form(
key: _formKey,
child: Padding(
padding: EdgeInsets.all(20.0),
child: Column(
children: <Widget>[
Container(
child: Center(
child: Column(
children: <Widget>[
Padding(
padding: EdgeInsets.all(20.0),
child: Text(
widget.name,
textAlign: TextAlign.center,
style: new TextStyle(
fontSize: 25.0,
color: primary,
fontWeight: FontWeight.bold,
),
),
),
Row(
children: <Widget> [
new Expanded(child: new DropDownField(
controller: currencySelected,
labelText: getTranslated((context), "currency_hint"),
enabled: true,
itemsVisibleInDropdown: 4,
items: currencycategories,
onValueChanged: (dynamic value) {
selectCurrency = value;
},
value: selectCurrency,
required: false,
),
flex: 2,
),
new SizedBox(
width: 10.0,
),
new Expanded(child: TextFormField(
validator: (input) {
if (input.isEmpty) return 'Please fill up the text fields';
},
controller: amount,
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: getTranslated((context), "budget_enter"),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: secondary),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: secondary),
),
),
),
flex: 2,
)],
),
Padding(
padding: EdgeInsets.all(20.0),
child: ElevatedButton(
onPressed: () async {
final FirebaseAuth _auth = FirebaseAuth
.instance;
final User user = _auth.currentUser;
final uid = user.uid;
if(!_formKey.currentState.validate()){
return;
}
_formKey.currentState.save();
collect.add({
'name': this.widget.name,
'currency': selectCurrency,
'amount': amount.text,
});
amount.text = "";
Navigator.pop(context);
},
child: Text(getTranslated((context), "save_button").toUpperCase(), style: TextStyle (
fontSize: 14,
)),
style: ButtonStyle(
padding: MaterialStateProperty.all<EdgeInsets>(EdgeInsets.all(20.0)),
foregroundColor: MaterialStateProperty.all<Color>(Colors.white),
backgroundColor: MaterialStateProperty.all<Color>(Colors.pink),
shape: MaterialStateProperty.all<RoundedRectangleBorder>(
RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
side: BorderSide(color: secondary)
),
),
),
),
)
],
),
)
)
],
),
)
);
}
}
检索到列表查看代码
import 'package:flutter/material.dart';
import 'package:monger_app/localization/localization_constants.dart';
import 'package:monger_app/page/transaction.dart';
import 'package:monger_app/theme/colors.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import './transaction.dart' as expense;
import './transaction.dart' as income;
class TransactionMonthly extends StatefulWidget {
@override
_TransactionMonthlyState createState() => _TransactionMonthlyState();
}
class _TransactionMonthlyState extends State<TransactionMonthly> with SingleTickerProviderStateMixin {
TabController controller;
@override
void initState() {
controller = new TabController(vsync: this, length: 2);
super.initState();
}
@override
void dispose() {
controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(getTranslated(context, 'budget_title'),),
elevation: 0,
brightness: Brightness.light,
backgroundColor: primary,
leading: IconButton(
onPressed: (){
Navigator.pop(context, MaterialPageRoute(builder: (context) => Transactions()));
},
icon: Icon(Icons.arrow_back_ios,
size: 20,
color: Colors.black,),
),
),
body: StreamBuilder(
stream: FirebaseFirestore.instance.collection('Budget').snapshots(),
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.hasData) {
return ListView(
children: snapshot.data.docs.map((document) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(children: [
SizedBox(width: 10,),
Text(document.get('name'),style: TextStyle(fontSize: 16,
color: primary,
fontWeight: FontWeight.w600
),),
],
),
SizedBox(height: 10,),
Row(children: [
SizedBox(width: 10,),
Text(document.get('currency'),style: TextStyle(fontSize: 16,
color: primary,
fontWeight: FontWeight.w600
),),
SizedBox(width: 10,),
Text(document.get('amount'),style: TextStyle(fontSize: 16,
color: primary,
fontWeight: FontWeight.w600
),),
],
),
SizedBox(height: 8,),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
GestureDetector(
onTap: (){
Widget cancelButton = FlatButton(child: Text("Cancel"),
onPressed: (){
Navigator.pop(context);
},
);
Widget deleteButton = FlatButton(child: Text("Delete"),
onPressed: (){
FirebaseFirestore.instance.collection('Budget').doc(document.id).delete();
Navigator.pop(context);
},
);
showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text('Delete Budget'),
content: Text('Are you sure want to delete it?'),
actions: [
cancelButton,
deleteButton,
],
),
);
//_showDeleteDialog();
//_showDeleteDialog(document: document);
},
child: Row(
children: [
Icon(Icons.delete_forever_outlined,
color: Colors.red,
),
SizedBox(width: 6,),
Text('Delete', style: TextStyle(fontSize: 16,
color: Colors.red,
fontWeight: FontWeight.w600
), ),
],
),
)
],
)
],)
);
}).toList(),
);
}
return Center(
child: CircularProgressIndicator(),
);
}
),
);
}
}
我想你想要的是一种按名称分组,这样你就可以在你的例子中用 160 来显示食物类别,而不是同一类别的两倍(如果我错了请纠正我)。我的建议是首先创建一个名为 Budget
的 class 以及您的三个属性 name, currency and amount
。当您在 TransactionMonthly Streambuilder
中收到数据时,您需要按名称对快照数据进行分组。完成后,您将创建一个预算列表 List<Budget> budgets
,以便您添加每个预算名称的金额总和。
这里有一个示例代码,您可以简单地复制粘贴并在 DartPad 上自行试用:
import 'package:collection/collection.dart';
//DATA coming from your Firebase collection
Map<String, dynamic> data1 = {
'name':"Food",
'currency': "IDR",
'amount': 100,
};
Map<String, dynamic> data2 = {
'name':"Food",
'currency': "IDR",
'amount': 60,
};
Map<String, dynamic> data3 = {
'name':"Beauty",
'currency': "USD",
'amount': 120,
};
//Your Budget class
class Budget{
String currency;
String name;
int amount;
@override
String toString(){
return "Budget: {currency: $currency, name: $name, amount: $amount}";
}
Budget({required this.currency, required this.name, required this.amount});
}
void main(){
List<Map<String, dynamic>> snapshot = [data1, data2, data3];
List<Budget> budgets = [];
//you group your budgets by name so you will have: {'Food': [data1, data2], 'Beauty':[data3]}
final groupByName = groupBy(snapshot, (Map<String, dynamic> doc)=>doc['name']);
print(groupByName);
int totalAmount = 0;
String currency = "";
groupByName.forEach((name, value){
//because we grouped by name every value will have same currency
currency = value[0]['currency'];
//Here we calculate the sum of all Food
totalAmount = value.map((e)=>e['amount']).reduce((v, e)=> v+e);
budgets.add(Budget(currency: currency, amount: totalAmount, name: name));
});
//budgets is your final list to use in your listView
print(budgets);
}