Search code examples
jsonflutterlistdartflutter-getx

Flutter Expandable Listview


I have the below list of objects that am trying to make into an expandable list grouped by month. Which is a value in the list.

{
   "status":"Success",
   "payments":[
      {
         "id":291,
         "user":{
            "id":12,
            "userID":"cvWLyHRla",
            "name":"Bill Obama",
            "email":"email@user1",
            "username":"username1",
            "profilePic":null,
            "created_at":"2023-05-08T00:52:11.000000Z"
         },
         "userID":12,
         "groupID":28,
         "paymentDueDate":"2023-11-01",
         "paymentDate":null,
         "amount":1000,
         "forDuration":"November",
         "proofOfPayment":null,
         "paymentMode":null,
         "paymentID":null,
         "paymentToken":null,
         "approvedBy":null,
         "approvedByUser":null,
         "approvedAt":null,
         "created_at":"2023-10-30T07:52:30.000000Z",
         "status":"pending",
         
      },
      {
         "id":290,
         "user":{
            "id":8,
            "userID":"yuwrgojsvIXqGeAzT18bTxbObEG3",
            "name":"Obama Clinton",
            "email":"email@user2",
            "username":"username2",
            "profilePic":"645866b914fu.jpg",
            "created_at":"2023-05-07T23:01:24.000000Z"
         },
         "userID":8,
         "groupID":28,
         "paymentDueDate":"2023-11-01",
         "paymentDate":"2023-10-30",
         "amount":1000,
         "forDuration":"November",
         "proofOfPayment":null,
         "paymentMode":"MobileMoney",
         "paymentID":"5888699-999",
         "paymentToken":null,
         "approvedBy":null,
         "approvedByUser":null,
         "approvedAt":"2023-10-30 07:53:15",
         "created_at":"2023-10-30T07:52:30.000000Z",
         "status":"paid",
         
      }
   ]
}

Am trying to create a flutter expandable list based on the "forDuration". So for each "forDuration" i should have children of the name, email, amount for all Users for that period. I have the below Listview.builder code but it is not showing the expansion tiles. Please kindly help. Below is what i have tried but the outcome is not as desired.

ListView.builder(
  itemCount: controller.groupPaymentResponse.value?.payments?.length ?? 0,
  itemBuilder: (BuildContext context, int index) {
    var e = controller.groupPaymentResponse.value!.payments![index];
      bool sameforDuration = false;
      if (controller.groupPaymentResponse.value!.payments![index + 1].forDuration ==
        controller.groupPaymentResponse.value!.payments![index]) {
            bool sameforDuration = true;
        }
      var image = e.user!.profilePic == null ? userPlaceHolder : "${e.user!.imagePath}/${e.user!.profilePic}";
      return ExpansionTile(
        title: Text(
          e.forDuration.toString(),
        ),
          children: [Text(e.user!.name!), Text(e.user!.email!), Text(e.amount.toString())],
      );
      }),

Solution

  • You need to modify(group) your list to get this result

    You can run it in dartpad I already coded it and need just a click on that link. Output is following screenshot

    import 'package:flutter/material.dart';
    import "package:collection/collection.dart";
    
    void main() => runApp(MyApp());
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Flutter Demo',
          debugShowCheckedModeBanner: false,
          theme: ThemeData(
            colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
            useMaterial3: true,
          ),
          home: const MyHomePage(title: 'Flutter Demo Home Page'),
        );
      }
    }
    
    class MyHomePage extends StatefulWidget {
      final String title;
    
      const MyHomePage({
        Key? key,
        required this.title,
      }) : super(key: key);
    
      @override
      State<MyHomePage> createState() => _MyHomePageState();
    }
    
    class _MyHomePageState extends State<MyHomePage> {
      late Map<String, List<TestingObj>> groupedItemMap;
    
      List<TestingObj> testingItems = [
        TestingObj(
          "Book",
          "100000",
          "November",
        ),
        TestingObj(
          "Pencil",
          "100",
          "November",
        ),
        TestingObj(
          "Eraser",
          "1000",
          "December",
        ),
        TestingObj(
          "Ruler",
          "100000",
          "September",
        ),
        TestingObj(
          "Bag",
          "100000",
          "September",
        ),
        TestingObj(
          "Paper",
          "100000",
          "September",
        ),
      ];
    
      @override
      void initState() {
        groupedItemMap = groupBy(testingItems, (entry) => entry.month);
    
        print(groupedItemMap.toString());
    
        super.initState();
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          body: ListView.builder(
              itemBuilder: (context, index) => ExpansionTile(
                    title: Text(
                      groupedItemMap.entries.elementAt(index).key,
                    ),
                    children: groupedItemMap.entries
                        .elementAt(index)
                        .value
                        .map((item) => Text(item.itemName))
                        .toList(),
                  ),
              itemCount: groupedItemMap.length),
        );
      }
    }
    
    class TestingObj {
      final String itemName;
      final String profit;
      final String month;
    
      TestingObj(this.itemName, this.profit, this.month);
    }
    

    Result images