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:
References
- https://pub.dev/packages/table_calendar
- https://pub.dev/documentation/table_calendar/latest/table_calendar/TableCalendar-class.html
- https://protocoderspoint.com/flutter-calender-widget-example-table-calender-widget/