Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Listview group by date Dart

I've been trying to get some messages ordered by date, but I'm not getting it working. I have tried different packages like grouped_list and sticky_headers.

With sticky_headers I managed to get a header above every post but that's not what I want. I want to have the messages sorted by day. Like the image below:
Application example

Below I have an dataset with de data I get from my API. My intention is to get 40 messages from the API. Those 40 messages are sorted by time only the messages must be grouped by day in the app as the image above.

Edit: After some playing with sticky_header package on flutter. I have now managed to get the headers. Only do not manage to get the messages under the correct header.

Dataset:

[
  {
    "time": "2020-06-16T10:31:12.000Z",
    "message": "P2 BGM-01 HV buiten materieel (Gas lekkage) Franckstraat Arnhem 073631"
  },
  {
    "time": "2020-06-16T10:29:35.000Z",
    "message": "A1 Brahmslaan 3862TD Nijkerk 73278"
  },
  {
    "time": "2020-06-16T10:29:35.000Z",
    "message": "A2 NS Station Rheden Dr. Langemijerweg 6991EV Rheden 73286"
  },
  {
    "time": "2020-06-15T09:41:18.000Z",
    "message": "A2 VWS Utrechtseweg 6871DR Renkum 74636"
  },
  {
    "time": "2020-06-14T09:40:58.000Z",
    "message": "B2 5623EJ : Michelangelolaan Eindhoven Obj: ziekenhuizen 8610 Ca CATH route 522 PAAZ Rit: 66570"
  }
]
like image 230
Simon Avatar asked Jun 23 '20 08:06

Simon


People also ask

How do I group a list by date in flutter?

Use collection package to use groupBy function. I hope this snippet will help you to start constructing your UI. You can use ListView widget for list items in each group. Go through DateTime, DateFormat classes to handle date, time values.

How do I use ListView separated in flutter?

separated. In Flutter, you can use ListView. separated to easily create a list view whose items are separated by separators (or dividers). A separator only appears between two list items and never stands before the first or sits after the last item.


4 Answers

First, breakdown your code to get group by date map from your dataset. Then use this map to construct the UI.

Use collection package to use groupBy function.

import "package:collection/collection.dart";

void main() {
  final dataSet = [
    {
      "time": "2020-06-16T10:31:12.000Z",
      "message": "Message1",
    },
    {
      "time": "2020-06-16T10:29:35.000Z",
      "message": "Message2",
    },
    {
      "time": "2020-06-15T09:41:18.000Z",
      "message": "Message3",
    },
  ];

  var groupByDate = groupBy(dataSet, (obj) => obj['time'].substring(0, 10));
  groupByDate.forEach((date, list) {
    // Header
    print('${date}:');

    // Group
    list.forEach((listItem) {
      // List item
      print('${listItem["time"]}, ${listItem["message"]}');
    });
    // day section divider
    print('\n');
  });
}

Output:

2020-06-16:
2020-06-16T10:31:12.000Z, Message1
2020-06-16T10:29:35.000Z, Message2


2020-06-15:
2020-06-15T09:41:18.000Z, Message3

I hope this snippet will help you to start constructing your UI. You can use ListView widget for list items in each group.

Go through DateTime, DateFormat classes to handle date, time values.

like image 52
Murali Krishna Regandla Avatar answered Oct 10 '22 12:10

Murali Krishna Regandla


There are some dart.pub packages called sticky_grouped_list and grouped_list (mentioned in your question). They have done a good work around group elements by a common property. I have tried sticky_grouped_list and besides I don't have used in your specific scenario it's seems to apply to it, once the Lists can group elements by a dynamic type.

Beyond the appearance, the main functional difference between your code and that example is they have used a DateTime element instead a String as a better manner to group the list. The sticky group list view is interesting due the fact the current date stick on the top of screen when it's rolled down.

enter image description here

instead of using a ListView create a GroupedListView Widget:

  GroupedListView<dynamic, String>(
    elements: _elements,
    groupBy: (element) => element['group'],
    groupSeparatorBuilder: (String groupByValue) => Text(groupByValue),
    itemBuilder: (context, dynamic element) => Text(element['name']),
    order: GroupedListOrder.ASC,
  ),

With the StickyGroupedListView you also can group by a custom object:

StickyGroupedListView<CustomObject, DateTime>(
  elements: pedidos,
  order: StickyGroupedListOrder.ASC,
  groupBy: (CustomObject element) => DateTime(
      element.dateGroup.year,
      element.dateGroup.month,
      element.dateGroup.day),
  groupSeparatorBuilder: (CustomObject element) =>
      renderDataCabecalho(element),
  itemBuilder: (context, element) {
    return _buildPedidoItemView(element, context);
  },
),

If it don't apply to your needs may you could get some insights on their approach to group elements by.

like image 41
Cassio Seffrin Avatar answered Oct 10 '22 11:10

Cassio Seffrin


If the API supports sorting, obtaining results in the correct order will be the simplest, and most high-performance solution.

like image 34
Richard Avatar answered Oct 10 '22 11:10

Richard


You should be able to achieve that by some custom logic on date. Check if two consecutive Dates are same if not add a Text Header in between those list items.

Heres the implementation of above approach.

import 'package:flutter/material.dart';
import 'package:intl/intl.dart';

void main() {
  final dateString = '2020-06-16T10:31:12.000Z';
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);
  final String title;
  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
 
  List<Map> list = [
    {
      "time": "2020-06-16T10:31:12.000Z",
      "message":
          "P2 BGM-01 HV buiten materieel (Gas lekkage) Franckstraat Arnhem 073631"
    },
    {
      "time": "2020-06-16T10:29:35.000Z",
      "message": "A1 Brahmslaan 3862TD Nijkerk 73278"
    },
    {
      "time": "2020-06-16T10:29:35.000Z",
      "message": "A2 NS Station Rheden Dr. Langemijerweg 6991EV Rheden 73286"
    },
    {
      "time": "2020-06-15T09:41:18.000Z",
      "message": "A2 VWS Utrechtseweg 6871DR Renkum 74636"
    },
    {
      "time": "2020-06-14T09:40:58.000Z",
      "message":
          "B2 5623EJ : Michelangelolaan Eindhoven Obj: ziekenhuizen 8610 Ca CATH route 522 PAAZ Rit: 66570"
    }
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: ListView.builder(
            itemCount: list.length,
            itemBuilder: (_, index) {
              bool isSameDate = true;
              final String dateString = list[index]['time'];
              final DateTime date = DateTime.parse(dateString);
              final item = list[index];
              if (index == 0) {
                isSameDate = false;
              } else {
                final String prevDateString = list[index - 1]['time'];
                final DateTime prevDate = DateTime.parse(prevDateString);
                isSameDate = date.isSameDate(prevDate);
              }
              if (index == 0 || !(isSameDate)) {
                return Column(children: [
                  Text(date.formatDate()),
                  ListTile(title: Text('item $index'))
                ]);
              } else {
                return ListTile(title: Text('item $index'));
              }
            }),
      ),
    );
  }
}

const String dateFormatter = 'MMMM dd, y';

extension DateHelper on DateTime {
  
   String formatDate() {
     final formatter = DateFormat(dateFormatter);
      return formatter.format(this);
  }
  bool isSameDate(DateTime other) {
    return this.year == other.year &&
        this.month == other.month &&
        this.day == other.day;
  }

  int getDifferenceInDaysWithNow() {
    final now = DateTime.now();
    return now.difference(this).inDays;
  }
}

Output

enter image description here

like image 6
Mahesh Jamdade Avatar answered Oct 10 '22 12:10

Mahesh Jamdade