skip to Main Content

I have a list of transactions and i want to show total expense or balance at last index of listview..

I have taken expTotal for total Expense and i am initializing total before build method

its showing proper result when i have few datas but when i add more data and scroll listview, expTotal showing all time with some increments

and even if i place int expTotal=0 inside widget build..its showing the same.

here is my code

int expTotal=0;

@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) {
                        //ListTile for Total
                        return ListTile(
                          tileColor: Colors.grey,
                          leading: CircleAvatar(
                            backgroundColor: Colors.grey,
                          ),
                          title: Center(child: Text('Total ')),
                          trailing: Text(expTotal.toString()),
                        );
                      }

                      final transactionModel = transactionList[index];

                      if(transactionModel.isExpense==true)
                        expTotal=expTotal+transactionModel.amount;
                      else
                        expTotal=expTotal-transactionModel.amount;

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

3

Answers


  1. Instead of

    int expTotal=0;
    

    you could write this to calculate it on the spot whenever you need it

    int get expTotal =>
        transactionList.fold<int>(0, (value, element) =>
        element.isExpanse
            ? value + element.amount
            : value - element.amount);
    

    Then you can leave out this part

    if(transactionModel.isExpense==true)
      expTotal=expTotal+transactionModel.amount;
    else
      expTotal=expTotal-transactionModel.amount;
    

    and then it should work as expected while leaving the rest of the code the same

    Login or Signup to reply.
  2. From the Flutter documentation:

    In contrast to the default ListView constructor, which requires
    creating all items at once, the ListView.builder() constructor creates
    items as they’re scrolled onto the screen.

    Your code calculating expTotal expects the builder to pass through the list completely and only once, giving you an exact total, but in reality the builder is only building items that scroll onto the screen, so your expTotal is only triggered for a subset of the items that are displayed. Worse, if you scroll backwards and forwards, the visible elements would be counted in expTotal each time they are displayed.

    It would be better to calculate the expTotal at the top of the build method, rather than inside the ListView.builder:

    @override
    Widget build(BuildContext context) {
      int expTotal = 0;
    
      for (int i=0; i<transactionList.length; i++) {
        if(transactionModel.isExpense==true)
          expTotal=expTotal+transactionModel.amount;
        else
          expTotal=expTotal-transactionModel.amount;
      }
    
      return Scaffold
      .....
    }
    
    Login or Signup to reply.
  3. When you scroll through the list, the builder rebuilds widgets, and if you are performing calculations inside the builder, it can lead to incorrect results due to repeated calculations. You should calculate the total before building the list. Editing your provided code, you should have something similar to the below:

    @override
    Widget build(BuildContext context) {
      int expTotal = transactionList.fold(0, (total, transaction) {
    return transaction.isExpense
        ? total + transaction.amount
        : total - transaction.amount;
      });
        
      return Scaffold(
        // other things
        body: Padding(
          padding: const EdgeInsets.all(8.0),
          child: Column(
            children: [
              // Some other things
              Expanded(
                child: ListView.builder(
                    padding: EdgeInsets.zero,
                    itemCount: transactionList.length + 1,
                    itemBuilder: (context, index) {
                      if (index == transactionList.length) {
                        // list tile for total
                        return ListTile(
                          // others
                          trailing: Text(expTotal.toString()),
                        );
                      }
    
                      final transactionModel = transactionList[index];
    
                      // transaction tile
                      return ListTile(
                        // others
                        trailing: Text(
                          transactionModel.amount.toString(),
                          style: TextStyle(
                              color: transactionModel.isExpense
                                  ? Colors.red
                                  : Colors.blue),
                        ),
                      );
                    }),
              ),
            ],
          ),
        ),
      );
    }
    

    You could also move the computation from the build method to initstate.

    int expTotal = 0;
    
      @override
      void initState() {
        super.initState();
        expTotal = transactionList.fold(0, (total, transaction) {
          return transaction.isExpense
              ? total + transaction.amount
              : total - transaction.amount;
        });
      }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search