如何在Dart中通过收入总和减支出总和计算并显示余额?
解决Flutter收支追踪APP中计算并显示余额的问题
你可以在获取所有交易数据的StreamBuilder中,直接遍历每条交易记录,区分收入和支出并分别累加,最后通过总收入 - 总支出得到余额。以下是修改后的完整代码:
import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:daily_expense/constants.dart'; import 'package:firebase_auth/firebase_auth.dart'; import 'package:flutter/material.dart'; import '../../../size_config.dart'; class TopBalanceCard extends StatelessWidget { TopBalanceCard({Key? key}) : super(key: key); final FirebaseFirestore _firebaseFirestore = FirebaseFirestore.instance; @override Widget build(BuildContext context) { return Padding( padding: const EdgeInsets.all(10.0), child: Container( height: getProportionateScreenHeight(200), decoration: BoxDecoration( borderRadius: BorderRadius.circular(15), color: Colors.blueGrey[100], ), child: Center( child: Column( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ Text( 'B A L A N C E', style: TextStyle( color: kSecondaryColor, fontSize: getProportionateScreenHeight(18)), ), StreamBuilder<QuerySnapshot>( stream: _firebaseFirestore .collection('new transactions') .where("UID", isEqualTo: FirebaseAuth.instance.currentUser!.email) .snapshots(), builder: (context, snapshot) { // 处理数据加载状态 if (snapshot.connectionState == ConnectionState.waiting) { return const CircularProgressIndicator(); } var totalIncome = 0; var totalExpense = 0; final tran = snapshot.data?.docs; if (tran != null) { for (var doc in tran) { // 获取单条交易的类型和金额 String type = doc.get('incomeOrExpense'); int amount = int.parse(doc.get('amount')); // 根据交易类型累加对应金额 if (type.toLowerCase() == 'income') { totalIncome += amount; } else if (type.toLowerCase() == 'expense') { totalExpense += amount; } } } // 计算最终余额 final finalBalance = totalIncome - totalExpense; return Text( '₹ $finalBalance', style: TextStyle( color: kTextColor, fontSize: getProportionateScreenHeight(35)), ); }), Padding( padding: const EdgeInsets.symmetric(horizontal: 20.0), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Row( children: [ Container( padding: const EdgeInsets.all(10), decoration: BoxDecoration( shape: BoxShape.circle, color: Colors.grey[200]), child: const Center( child: Icon( Icons.arrow_upward_rounded, color: Colors.green, ), ), ), const SizedBox(width: 10), Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Income', style: TextStyle( color: kTextColor, fontSize: getProportionateScreenHeight(18)), ), const SizedBox(height: 5), StreamBuilder<QuerySnapshot>( stream: _firebaseFirestore .collection('new transactions') .where("UID", isEqualTo: FirebaseAuth .instance.currentUser!.email) .where("incomeOrExpense", isEqualTo: "income") .snapshots(), builder: (context, snapshot) { var finalIncome = 0; final tran = snapshot.data?.docs; if (tran != null) { for (var i in tran) { finalIncome += int.parse(i.get('amount')); } } return Text( '₹ $finalIncome', style: TextStyle( fontWeight: FontWeight.bold, fontSize: getProportionateScreenHeight(20)), ); }) ], ) ], ), Padding( padding: const EdgeInsets.symmetric(horizontal: 20), child: Row( children: [ Container( padding: const EdgeInsets.all(10), decoration: BoxDecoration( shape: BoxShape.circle, color: Colors.grey[200]), child: const Center( child: Icon( Icons.arrow_downward_rounded, color: Colors.red, ), ), ), const SizedBox(width: 10), Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Expense', style: TextStyle( color: kTextColor, fontSize: getProportionateScreenHeight(18)), ), const SizedBox(height: 5), StreamBuilder<QuerySnapshot>( stream: _firebaseFirestore .collection('new transactions') .where("UID", isEqualTo: FirebaseAuth .instance.currentUser!.email) .where('incomeOrExpense', isEqualTo: 'Expense') .snapshots(), builder: (context, snapshot) { var finalExpense = 0; final tran = snapshot.data?.docs; if (tran != null) { for (var i in tran) { finalExpense += int.parse(i.get('amount')); } } return Text( '₹ $finalExpense', style: TextStyle( fontWeight: FontWeight.bold, fontSize: getProportionateScreenHeight(20)), ); }) ], ) ], ), ) ], ), ) ], ), ), ), ); } }
关键修改说明:
- 增加加载状态处理:当数据还在加载时显示加载指示器,避免界面空白
- 简化余额计算逻辑:直接遍历所有交易文档,区分收入/支出类型后分别累加,最后计算余额
- 优化收入/支出累加代码:移除了多余的中间列表转换步骤,直接在遍历过程中完成金额累加,提升代码效率
内容的提问来源于stack exchange,提问作者Rakshit
相关产品推荐
相关产品推荐

