Search code examples
flutterlistviewcalendarstate-management

Listview is not showing anything


I'm developing a Flutter calendar app that enables users to add events to specific dates. The calendar effectively displays events as markers on the dates, and tapping on a date should display the corresponding events in a list view beneath the calendar. However, I'm encountering an issue: when I tap off a date and then return to it, the events that were previously shown in the list view disappear. The events are being saved in a map so there is probably an issue with how teh program is outputting them

I use the EventList class to output the events:

class EventList extends StatelessWidget {
  final List<Event> events;

  const EventList({
    required this.events,
    Key? key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    if (events.isEmpty) {
      return Container(
        padding: const EdgeInsets.all(16.0),
        child: const Text(
          'No Events',
          style: TextStyle(color: Colors.grey),
        ),
      );
    } else {
      return Expanded(
        child: ListView.builder(
          itemCount: events.length,
          itemBuilder: (context, index) {
            final event = events[index];
            return Container(
              margin:
                  const EdgeInsets.symmetric(vertical: 4.0, horizontal: 12.0),
              decoration: const BoxDecoration(
                color: Colors.white,
                border: Border(bottom: BorderSide(color: Colors.grey)),
              ),
              child: ListTile(
                onTap: () => print(""),
                title: Text(event.title),
              ),
            );
          },
        ),
      );
    }
  }
}

Code calling the class:

  List<Event> _getEventsForDay(DateTime day) {
    return events[day] ?? [];
  }
EventList(
            events: _getEventsForDay(_selectedDay!),
          ),

The events look like they are being saved in the map but I don't really know what the error is. Here is the full code

// ignore_for_file: use_build_context_synchronously

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

class Event {
  final String title;
  final DateTime dateTime;

  Event(this.title, this.dateTime);
}

void main() {
  runApp(const MaterialApp(
    home: Calendar(),
  ));
}

class Calendar extends StatefulWidget {
  const Calendar({Key? key}) : super(key: key);

  @override
  State<Calendar> createState() => _CalendarState();
}

class _CalendarState extends State<Calendar> {
  final DateTime _focusedDay = DateTime.now();
  DateTime? _selectedDay;
  Map<DateTime, List<Event>> events = {};
  final TextEditingController _eventController = TextEditingController();

  @override
  void initState() {
    super.initState();
    _selectedDay = _focusedDay;
  }

  List<Event> _getEventsForDay(DateTime day) {
    return events[day] ?? [];
  }

  void _showEventInputDialog() async {
    final selectedDate = await showDatePicker(
      context: context,
      initialDate: _focusedDay,
      firstDate: DateTime(2020),
      lastDate: DateTime(2030),
    );

    if (selectedDate != null) {
      setState(() {
        _selectedDay = selectedDate;
      });

      showModalBottomSheet(
        context: context,
        builder: (context) {
          return Container(
            padding: const EdgeInsets.all(16.0),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              mainAxisSize: MainAxisSize.min,
              children: [
                Text(
                  'Add Event - ${_selectedDay!.toString().substring(0, 10)}',
                  style: const TextStyle(fontWeight: FontWeight.bold),
                ),
                const SizedBox(height: 16.0),
                TextField(
                  controller: _eventController,
                  decoration: const InputDecoration(hintText: 'Event Name'),
                ),
                const SizedBox(height: 16.0),
                ElevatedButton(
                  onPressed: () {
                    if (_eventController.text.trim().isNotEmpty) {
                      setState(() {
                        final newEvent = Event(
                          _eventController.text.trim(),
                          _selectedDay!,
                        );

                        if (events[_selectedDay!] == null) {
                          events[_selectedDay!] = [newEvent];
                        } else {
                          events[_selectedDay!]!.add(newEvent);
                        }

                        _eventController.clear();
                      });

                      Navigator.pop(context);
                    }
                  },
                  child: const Text('Add Event'),
                ),
              ],
            ),
          );
        },
      );
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Calendar'),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _showEventInputDialog,
        child: const Icon(Icons.add),
      ),
      body: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          TableCalendar(
            calendarBuilders: CalendarBuilders(
              markerBuilder: (context, date, events) {
                if (events.isNotEmpty) {
                  return Positioned(
                    bottom: 0,
                    child: Container(
                      width: 6,
                      height: 6,
                      decoration: const BoxDecoration(
                        shape: BoxShape.circle,
                        color: Colors.blue,
                      ),
                    ),
                  );
                }
                return const SizedBox();
              },
            ),
            availableGestures: AvailableGestures.all,
            selectedDayPredicate: (day) {
              return isSameDay(_selectedDay, day);
            },
            focusedDay: _focusedDay,
            firstDay: DateTime.utc(2020, 01, 01),
            lastDay: DateTime.utc(2030, 01, 01),
            onDaySelected: (selectedDay, focusedDay) {
              setState(() {
                _selectedDay = selectedDay;
              });
            },
            eventLoader: _getEventsForDay,
          ),
          const SizedBox(height: 8.0),
          const Divider(
            indent: 4,
            endIndent: 16,
            thickness: 1,
            color: Colors.grey,
          ),
          EventList(
            events: _getEventsForDay(_selectedDay!),
          ),
        ],
      ),
    );
  }
}

class EventList extends StatelessWidget {
  final List<Event> events;

  const EventList({
    required this.events,
    Key? key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    if (events.isEmpty) {
      return Container(
        padding: const EdgeInsets.all(16.0),
        child: const Text(
          'No Events',
          style: TextStyle(color: Colors.grey),
        ),
      );
    } else {
      return Expanded(
        child: ListView.builder(
          itemCount: events.length,
          itemBuilder: (context, index) {
            final event = events[index];
            return Container(
              margin:
                  const EdgeInsets.symmetric(vertical: 4.0, horizontal: 12.0),
              decoration: const BoxDecoration(
                color: Colors.white,
                border: Border(bottom: BorderSide(color: Colors.grey)),
              ),
              child: ListTile(
                onTap: () => print(""),
                title: Text(event.title),
              ),
            );
          },
        ),
      );
    }
  }
}

Solution

  • It's because when you add event in map the selected day value is: (2023-08-30 00:00:00.000)

    And when you tap on a day it gives : (2023-08-30 00:00:00.000Z)

    just update your onDaySelected:

      onDaySelected: (selectedDay, focusedDay) {
              setState(() {
                _selectedDay = DateTime.parse(
                    DateFormat('yyyy-MM-dd HH:mm:ss.SSS').format(selectedDay));
    
              });
            },