我正在尝试制作一个预算应用程序,每个预算都有自己的支出历史。每个支出历史都会有一个名为"budgetName"的变量,我可以使用下面的sqflite代码编译它并计算支出总额。
return await db.rawQuery("select sum(budgetSpent) as total from spending where budgetName ='" + budgetTitle + "'");
如果我在调用sqflite函数时尝试使用.then((value) {print(value);})
,并在调试控制台中查看每个预算的支出值,那么这就有效了。
但问题是,在调用函数时,我需要"budgetTitle",这样它就可以与支出的"budgetName"进行比较,以获得总支出金额。
所以我现在的情况是,我试图获得如下的支出金额:
child: BudgetCard(
budgetName: budget.budgetName,
budgetSpent: '${Provider.of<SpendingDatabaseHelper>(context, listen: false).getSpecificSpending(budget.budgetName}',
maxBudget: currency.format(int.parse(budget.maxBudget)),
svgIcon: iconListBudgetCards[budget.iconValue],
color: colorSwatch[budget.colorValue],
percentage: 0.5),
),
但它只返回Instance of 'Future<dynamic>'
,因为它在获取值之前需要等待。但我找不到其他方法,因为它需要传递"预算标题"。
非常感谢您的任何帮助、想法或建议!提前谢谢。
这是数据库代码:
String? budgetSpendingAmount;
getSpecificSpending(budgetTitle) async {
dynamic result =
await SpendingDatabaseHelper.instance.getSpendingAmount(budgetTitle);
String a = result.toString();
debugPrint('A: $a');
if (a == '[{total: null}]') {
a = currency.format(int.parse('000'.trim()));
budgetSpendingAmount = a;
print(budgetSpendingAmount);
} else {
String? b = a.replaceAll(RegExp(r'[{}[]-]+'), '');
String c = b.substring(b.indexOf(":") + 1);
budgetSpendingAmount = currency.format(int.parse(c.trim()));
}
notifyListeners();
}
Future getSpendingAmount(String budgetTitle) async {
Database db = await instance.database;
return await db.rawQuery("select sum(budgetSpent) as total from spending where ='" + budgetTitle + "'");
}
以下是我调用函数以获取支出金额数据的完整代码:
Widget build(BuildContext context) {
return FutureBuilder<List<Budget>>(
future: Provider.of<BudgetDatabaseHelper>(context).getBudgets(),
/// Displaying the data from the list
builder: (context, snapshot) {
if (!snapshot.hasData) {
return const Center();
}
return snapshot.data!.isEmpty
? const Flexible(
child: Center(
child: Padding(
padding: EdgeInsets.only(bottom: 80.0),
child: Text(
'You don't have any budget',
style: kCaption,
),
)))
: Flexible(
child: ListView.builder(
physics: const BouncingScrollPhysics(),
itemCount: snapshot.data!.length,
itemBuilder: (context, index) {
final budget = snapshot.data![index];
return Dismissible(
key: UniqueKey(),
background: const Align(
alignment: Alignment.centerRight,
child: Padding(
padding: EdgeInsets.only(bottom: 12.0, right: 24),
child: Icon(
IconlyLight.delete,
color: cRed,
size: 24,
),
),
),
direction: DismissDirection.endToStart,
onDismissed: (direction) {
snapshot.data!.removeAt(index);
Provider.of<BudgetDatabaseHelper>(context,
listen: false)
.removeMethod(budget.id!, budget.budgetName);
},
child: GestureDetector(
onTap: () => showModalBottomSheet(
backgroundColor: Colors.transparent,
context: context,
enableDrag: true,
isScrollControlled: true,
builder: (context) {
return DraggableScrollableSheet(
snap: true,
minChildSize: 0.43,
maxChildSize: 0.85,
initialChildSize: 0.43,
snapSizes: const [0.43, 0.85],
builder: (context, scrollController) {
return ClipRRect(
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(32),
topRight: Radius.circular(32)),
child: Container(
color: cWhite,
child: SingleChildScrollView(
controller: scrollController,
physics: const BouncingScrollPhysics(),
child: BudgetDetails(
id: budget.id!,
budgetName: budget.budgetName,
budgetSpent: 'budgetSpent',
colorValue:
colorSwatch[budget.colorValue],
maxBudget: currency.format(
int.parse(budget.maxBudget)),
svgIcon: iconListBudgetDetails[
budget.iconValue],
),
),
),
);
},
);
},
),
child: BudgetCard(
budgetName: budget.budgetName,
budgetSpent: '${Provider.of<SpendingDatabaseHelper>(context, listen: false).getSpecificSpending(budget.budgetName}',
maxBudget: currency.format(int.parse(budget.maxBudget)),
svgIcon: iconListBudgetCards[budget.iconValue],
color: colorSwatch[budget.colorValue],
percentage: 0.5),
),
);
},
),
);
},
);
}
在小部件树中使用provider
不是一个好主意。制作statefullWidget
在你的SpendingDatabaseHelper
中制作一个类似的getter
String? _budgetSpendingAmount;
String get budgetSpendingAmount=> _budgetSpendingAmount;
并像这样初始化_budgetSpendingAmount = currency.format(int.parse(c.trim()));
因此,使用这个getter,您可以在窗口小部件树中的任何位置访问这个值
Future<void> _getSpecificSpending(String budgetName)async{
try{
await Provider.of<SpendingDatabaseHelper>(context, listen: false).getSpecificSpending(budgetName);
} catch(e){
print('error :$e');
}
}
并在您的窗口小部件树中写下类似的内容
child: FutureBuilder(
future : _getSpecificSpending(budget.budgetName)
builder: (ctx,snapshot){
var spendDataProv=Provider.of<SpendingDatabaseHelper>(context, listen: false);
return snapshot.connectionState==ConnectionState.waiting ?
CircularProgressIndicator() :
BudgetCard(
budgetName: budget.budgetName,
budgetSpent:spendDataProv.budgetSpendingAmount ,
maxBudget: currency.format(int.parse(budget.maxBudget)),
svgIcon: iconListBudgetCards[budget.iconValue],
color: colorSwatch[budget.colorValue],
percentage: 0.5)
},
)
一些想法的
在BudgetCard小部件中使用FutureBuilder。然后,当您仍在等待未来完成时,您可以显示CircularProgressIndicator支出金额的位置。
或
使用布尔标志(在future方法的开头和结尾翻转该标志(来指示future是否结束。Flag false:显示progressIndicator,Flag true显示花费金额。
或
当调用Provider.of<BudgetDatabaseHelper>(context).getBudgets()
时,可以让方法getBudgets()
也用以后需要的信息填充一个数组。因此,在getBudgets()
方法中为每个预算名称调用Provider.of<SpendingDatabaseHelper>(context, listen: false).getSpecificSpending(budget.budgetName)
。