Skip to content

[Flutter] Use table_calendar Package To Create Calendar

Last Updated on 2021-10-13 by Clay

The calendar component is a component that is used in many applications, such as accounting and note-taking. When using Flutter for development, you can call the calendar kit developed by the predecessors instead of developed by yourself.

What I want to introduce today is the most popular calendar package on Flutter pub: table_calendar.


Preparation

First, you need to write the package you want to use in pubspec.yaml.

dependencies:
  flutter:
    sdk: flutter

  table_calendar: ^2.3.3


And use the following command to get the packages.

flutter pub get

Example

In below I will introduce step by step how to use code to call the package to create a calendar component.

This sample code is a bit long, if you want to try it out, you can look at the complete code in the next section.


Import packages

First, we need to import all the packages we need.

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

import 'package:intl/date_symbol_data_local.dart';
import 'package:table_calendar/table_calendar.dart';



(Optional) Set holiday

// Holiday will display red word
final Map<DateTime, List> _holidays = {
  DateTime(2021, 3, 1): ["228"],
};


In table_calendar, we can set the required holiday. Many items can be set here, the interface will be placed when the calendar object is created.


HomePage

// Main
void main() {
  initializeDateFormatting().then((_) => runApp(MyApp()));
}


// MyApp
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // Hide the top status bar
    SystemChrome.setEnabledSystemUIOverlays([]);
    return MaterialApp(
      home: HomePage(title: "Table Calender"),
      debugShowCheckedModeBanner: false,
    );
  }
}


// HomePage
class HomePage extends StatefulWidget {
  final String title;
  HomePage({Key key, this.title}) : super(key: key);

  @override
  _HomePageState createState() => _HomePageState();
}


This part is the starting form of the Flutter App: main() entry point and HomePage.

Then the next step is to write all the interactive functions in _HomePageState.


_HomePageState

class _HomePageState extends State<HomePage> with TickerProviderStateMixin {
  Map<DateTime, List> _events;
  List _selectedEvents;
  AnimationController _animationController;
  CalendarController _calendarController;

  @override
  void initState() {
    super.initState();

    // Today
    final _selectedDay = DateTime.now();

    // Events
    _events = {
      _selectedDay.add(Duration(days: 1)): [
        'Sleep all day',
      ],
      _selectedDay.add(Duration(days: 2)): [
        'Play PS4 Game',
        'Exercising',
        'Coding',
        'Sleeping',
        'Watch a movie',
        'Take a walk',
        'Surf on the internet'
      ],
    };

    _selectedEvents = _events[_selectedDay] ?? [];
    _calendarController = CalendarController();
    _animationController = AnimationController(
      vsync: this,
      duration: const Duration(milliseconds: 400),
    );

    _animationController.forward();
  }


  • _selectedEvents: Select the list of events
  • _animationController: Control animation
  • _calendarController: Objects that control the calendar component

The following _events are events I created. I imagine that I am making an App like a calendar, and a day is recording the activities that I may be engaged in.


Rewrite some functions (still under _HomePageState)

  @override
  void dispose() {
    _animationController.dispose();
    _calendarController.dispose();
    super.dispose();
  }

  void _onDaySelected(DateTime day, List events, List holidays) {
    print("CALLBACK: _onDaySelected");
    setState(() {
      _selectedEvents = events;
    });
  }

  void _onVisibleDaysChanged(DateTime first, DateTime last, CalendarFormat format) {
    print("CALLBACK: _onVisibleDaysChanged");
  }

  void _onCalendarCreated(DateTime first, DateTime last, CalendarFormat format) {
    print("CALLBACK: _onCalendarCreated");
  }


Here we rewrite some functions to allow us to see log messages when interacting with the calendar component. This part is written in the document of table_calendar.


The form of the interface arrangement (still under _HomePageState)

  // Basic interface
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Column(
        mainAxisSize: MainAxisSize.max,
        children: [
          _buildTableCalendar(),
          Expanded(child: _buildEventList()),
        ],
      ),
    );
  }


The most important thing is the layout of Column.

Then we will implement the two methods _buildTableCalendar() and _buildEventList().


_buildEventList() (still under _HomePageState)

// Event List
  Widget _buildEventList() {
    return ListView(
      children: _selectedEvents.map(
              (event) => Container(
            decoration: BoxDecoration(
              color: Colors.lightBlueAccent[100],
              border: Border.all(width: 0.8),
              borderRadius: BorderRadius.circular(12.0),
            ),
            margin: const EdgeInsets.symmetric(
              horizontal: 2.0,
              vertical: 1.0,
            ),
            child: ListTile(
              title: Text(event.toString()),
              onTap: () => print("${event} tapped!"),
            ),
          )
      ).toList(),
    );
  }


This is made with the ListView component and brought in the _events event that was initially set. Others are some parameter settings such as color, length and width.


_buildTableCalendar() (still under _HomePageState)

// Simple TableCalendar configuration (using Style)
  Widget _buildTableCalendar() {
    return TableCalendar(
      calendarController: _calendarController,
      events: _events,
      holidays: _holidays,
      startingDayOfWeek: StartingDayOfWeek.sunday,

      // Calendar
      calendarStyle: CalendarStyle(
        selectedColor: Colors.lightBlueAccent[400],
        todayColor: Colors.lightBlueAccent[100],
        markersColor: Colors.lightBlue[600],
        outsideDaysVisible: false,
      ),

      // Header
      headerStyle: HeaderStyle(
        formatButtonTextStyle:
        TextStyle().copyWith(
          color: Colors.white,
          fontSize: 15.0,
        ),
        formatButtonDecoration: BoxDecoration(
          color: Colors.grey[600],
          borderRadius: BorderRadius.circular(8.0),
        ),
      ),

      // Operating
      onDaySelected: _onDaySelected,
      onVisibleDaysChanged: _onVisibleDaysChanged,
      onCalendarCreated: _onCalendarCreated,
    );
  }


This part is the most researched part of the calendar component.

I have not yet fully understand how to use each interface.

But as far as some examples on the Internet I have seen, there are really many things that can be changed.

The main thing is to create the TableCalendar component.

Please refer to the complete code below for the execution result. Even if spaces are added, it is within two hundred lines, which is actually a condensed example code.


Complete Code

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

import 'package:intl/date_symbol_data_local.dart';
import 'package:table_calendar/table_calendar.dart';


// Holiday will display red word
final Map<DateTime, List> _holidays = {
  DateTime(2021, 3, 1): ["228"],
};


// Main
void main() {
  initializeDateFormatting().then((_) => runApp(MyApp()));
}


// MyApp
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // Hide the top status bar
    SystemChrome.setEnabledSystemUIOverlays([]);
    return MaterialApp(
      home: HomePage(title: "Table Calender"),
      debugShowCheckedModeBanner: false,
    );
  }
}


// HomePage
class HomePage extends StatefulWidget {
  final String title;
  HomePage({Key key, this.title}) : super(key: key);

  @override
  _HomePageState createState() => _HomePageState();
}


class _HomePageState extends State<HomePage> with TickerProviderStateMixin {
  Map<DateTime, List> _events;
  List _selectedEvents;
  AnimationController _animationController;
  CalendarController _calendarController;

  @override
  void initState() {
    super.initState();

    // Today
    final _selectedDay = DateTime.now();

    // Events
    _events = {
      _selectedDay.add(Duration(days: 1)): [
        'Sleep all day',
      ],
      _selectedDay.add(Duration(days: 2)): [
        'Play PS4 Game',
        'Exercising',
        'Coding',
        'Sleeping',
        'Watch a movie',
        'Take a walk',
        'Surf on the internet'
      ],
    };

    _selectedEvents = _events[_selectedDay] ?? [];
    _calendarController = CalendarController();
    _animationController = AnimationController(
      vsync: this,
      duration: const Duration(milliseconds: 400),
    );

    _animationController.forward();
  }

  @override
  void dispose() {
    _animationController.dispose();
    _calendarController.dispose();
    super.dispose();
  }

  void _onDaySelected(DateTime day, List events, List holidays) {
    print("CALLBACK: _onDaySelected");
    setState(() {
      _selectedEvents = events;
    });
  }

  void _onVisibleDaysChanged(DateTime first, DateTime last, CalendarFormat format) {
    print("CALLBACK: _onVisibleDaysChanged");
  }

  void _onCalendarCreated(DateTime first, DateTime last, CalendarFormat format) {
    print("CALLBACK: _onCalendarCreated");
  }


  // Basic interface
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Column(
        mainAxisSize: MainAxisSize.max,
        children: [
          _buildTableCalendar(),
          Expanded(child: _buildEventList()),
        ],
      ),
    );
  }

  // Simple TableCalendar configuration (using Style)
  Widget _buildTableCalendar() {
    return TableCalendar(
      calendarController: _calendarController,
      events: _events,
      holidays: _holidays,
      startingDayOfWeek: StartingDayOfWeek.sunday,

      // Calendar
      calendarStyle: CalendarStyle(
        selectedColor: Colors.lightBlueAccent[400],
        todayColor: Colors.lightBlueAccent[100],
        markersColor: Colors.lightBlue[600],
        outsideDaysVisible: false,
      ),

      // Header
      headerStyle: HeaderStyle(
        formatButtonTextStyle:
        TextStyle().copyWith(
          color: Colors.white,
          fontSize: 15.0,
        ),
        formatButtonDecoration: BoxDecoration(
          color: Colors.grey[600],
          borderRadius: BorderRadius.circular(8.0),
        ),
      ),

      // Operating
      onDaySelected: _onDaySelected,
      onVisibleDaysChanged: _onVisibleDaysChanged,
      onCalendarCreated: _onCalendarCreated,
    );
  }

  // Event List
  Widget _buildEventList() {
    return ListView(
      children: _selectedEvents.map(
          (event) => Container(
            decoration: BoxDecoration(
              color: Colors.lightBlueAccent[100],
              border: Border.all(width: 0.8),
              borderRadius: BorderRadius.circular(12.0),
            ),
            margin: const EdgeInsets.symmetric(
              horizontal: 2.0,
              vertical: 1.0,
            ),
            child: ListTile(
              title: Text(event.toString()),
              onTap: () => print("${event} tapped!"),
            ),
          )
      ).toList(),
    );
  }
}


Output:

https://clay-atlas.com/wp-content/uploads/2021/03/Screen-Recording-2021-03-05-at-10.56.32-AM.mov

References


Read More

Leave a ReplyCancel reply

Exit mobile version