You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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)),
                                    );
                                  })
                            ],
                          )
                        ],
                      ),
                    )
                  ],
                ),
              )
            ],
          ),
        ),
      ),
    );
  }
}

关键修改说明:

  1. 增加加载状态处理:当数据还在加载时显示加载指示器,避免界面空白
  2. 简化余额计算逻辑:直接遍历所有交易文档,区分收入/支出类型后分别累加,最后计算余额
  3. 优化收入/支出累加代码:移除了多余的中间列表转换步骤,直接在遍历过程中完成金额累加,提升代码效率

内容的提问来源于stack exchange,提问作者Rakshit

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 08:25:32