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

Flutter中如何在ListView末尾显示总计金额?

问题原因

你遇到的问题根源在于ListView.builder的itemBuilder方法会被重复调用:当ListView滚动时,屏幕外的item会被销毁,新进入屏幕的item会触发itemBuilder重建。你原来的写法是在itemBuilder里逐个累加/扣除金额,每次itemBuilder执行都会修改expTotal,导致这个变量被重复计算,最终数值越来越大。

哪怕把expTotal放在build方法内,只要itemBuilder多次执行,还是会在每次构建item时重复累加——因为build执行一次,itemBuilder会执行transactionList.length +1次,每次执行都在修改同一个expTotal变量。

解决方案

核心思路是提前计算总金额,不在itemBuilder内做累加操作,确保总金额只计算一次(或按需实时计算,但不会重复累加)。

方法1:在build方法内提前计算总金额

在ListView.builder之前就计算好总金额,这样无论itemBuilder调用多少次,总金额都是固定的正确值:

@override
Widget build(BuildContext context) {
    // 提前计算总金额,仅在build执行时计算一次
    int expTotal = 0;
    for (var transaction in transactionList) {
      if (transaction.isExpense) {
        expTotal += transaction.amount;
      } else {
        expTotal -= transaction.amount;
      }
    }

    // 也可以用fold方法简化计算
    // int expTotal = transactionList.fold(0, (total, transaction) {
    //   return transaction.isExpense ? total + transaction.amount : total - transaction.amount;
    // });

    return Scaffold(
        backgroundColor: Colors.grey.shade100,
        body: Padding(
          padding: const EdgeInsets.all(8.0),
          child: Column(
            children: [
               Container(
                height: 400,
                 color: Colors.transparent,
              ),
              Expanded(
                child: ListView.builder(
                    padding: EdgeInsets.zero,
                    itemCount: transactionList.length + 1,
                    itemBuilder: (context, index) {

                      if (index == transactionList.length) {
                        return ListTile(
                          tileColor: Colors.grey,
                          leading: CircleAvatar(
                            backgroundColor: Colors.grey,
                          ),
                          title: Center(child: Text('Total ')),
                          trailing: Text(expTotal.toString()),
                        );
                      }

                      final transactionModel = transactionList[index];

                      return ListTile(
                        leading: CircleAvatar(
                          child: Text(transactionModel.id),
                        ),
                        title: Text(transactionModel.category),
                        trailing: Text(
                          transactionModel.amount.toString(),
                          style: TextStyle(
                              color: transactionModel.isExpense
                                  ? Colors.red
                                  : Colors.blue),
                        ),
                      );
                    }),
              ),
            ],
          ),
        ),
    );
  }

方法2:使用计算属性(Getter)

如果transactionList会动态变化,用Getter可以实时计算最新的总金额,代码更简洁:

// 在类中定义计算属性
int get expTotal {
  return transactionList.fold(0, (total, transaction) {
    return transaction.isExpense ? total + transaction.amount : total - transaction.amount;
  });
}

@override
Widget build(BuildContext context) {
    return Scaffold(
        backgroundColor: Colors.grey.shade100,
        body: Padding(
          padding: const EdgeInsets.all(8.0),
          child: Column(
            children: [
               Container(
                height: 400,
                 color: Colors.transparent,
              ),
              Expanded(
                child: ListView.builder(
                    padding: EdgeInsets.zero,
                    itemCount: transactionList.length + 1,
                    itemBuilder: (context, index) {

                      if (index == transactionList.length) {
                        return ListTile(
                          tileColor: Colors.grey,
                          leading: CircleAvatar(
                            backgroundColor: Colors.grey,
                          ),
                          title: Center(child: Text('Total ')),
                          trailing: Text(expTotal.toString()),
                        );
                      }

                      final transactionModel = transactionList[index];

                      return ListTile(
                        leading: CircleAvatar(
                          child: Text(transactionModel.id),
                        ),
                        title: Text(transactionModel.category),
                        trailing: Text(
                          transactionModel.amount.toString(),
                          style: TextStyle(
                              color: transactionModel.isExpense
                                  ? Colors.red
                                  : Colors.blue),
                        ),
                      );
                    }),
              ),
            ],
          ),
        ),
    );
  }
关键注意点

永远不要在ListView.builder的itemBuilder中做状态累加/修改操作,因为这个方法会随着列表滚动被频繁调用,任何在其中的状态修改都会导致不可预期的重复计算。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 16:25:04