Appointments in Flutter Event Calendar (SfCalendar)
6 Jun 202324 minutes to read
SfCalendar widget has a built-in capability to handle the appointment arrangement internally based on the CalendarDataSource. Appointment is a class, which holds the details about the appointment to be rendered in calendar.
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Container(
child: SfCalendar(
view: CalendarView.week,
dataSource: _getCalendarDataSource(),
),
),
),
);
}
_AppointmentDataSource _getCalendarDataSource() {
List<Appointment> appointments = <Appointment>[];
appointments.add(Appointment(
startTime: DateTime.now(),
endTime: DateTime.now().add(Duration(minutes: 10)),
subject: 'Meeting',
color: Colors.blue,
startTimeZone: '',
endTimeZone: '',
));
return _AppointmentDataSource(appointments);
}
class _AppointmentDataSource extends CalendarDataSource {
_AppointmentDataSource(List<Appointment> source){
appointments = source;
}
}
Calendar data source and mapping
CalendarDataSource
is an abstract class used to set the appointment datasource for calendar and has properties to map the custom appointments to the calendar Appointment
. Calendar supports full data binding to any type of List source. Specify the corresponding property override method to map the properties in the underlying data source to the calendar appointments in CalendarDataSource
.
Property Name | Description |
---|---|
getStartTime | Maps the property name of custom class, which is equivalent for startTime of Appointment . |
getEndTime | Maps the property name of custom class, which is equivalent for endTime of Appointment . |
getStartTimeZone | Maps the property name of custom class, which is equivalent for startTimeZone of Appointment . |
getEndTimeZone | Maps the property name of custom class, which is equivalent for endTimeZone of Appointment . |
getSubject | Maps the property name of custom class, which is equivalent for subject of Appointment . |
getColor | Maps the property name of custom class, which is equivalent for color of Appointment . |
isAllDay | Maps the property name of custom class, which is equivalent for isAllDay of Appointment . |
getRecurrenceRule | Maps the property name of custom class, which is equivalent for recurrenceRule of Appointment . |
getNotes | Maps the property name of custom class which is equivalent for notes of Appointment . |
getLocation | Maps the property name of custom class, which is equivalent for location of Appointment . |
getRecurrenceExceptionDates | Maps the property name of custom class, which is equivalent for recurrenceExceptionDates of Appointment . |
NOTE
- Custom appointment class should contain two date time fields as mandatory.
class MeetingDataSource extends CalendarDataSource {
MeetingDataSource(List<Meeting> source){
appointments = source;
}
@override
DateTime getStartTime(int index) {
return appointments![index].from;
}
@override
DateTime getEndTime(int index) {
return appointments![index].to;
}
@override
bool isAllDay(int index) {
return appointments![index].isAllDay;
}
@override
String getSubject(int index) {
return appointments![index].eventName;
}
@override
String getStartTimeZone(int index) {
return appointments![index].startTimeZone;
}
@override
String getEndTimeZone(int index) {
return appointments![index].endTimeZone;
}
@override
Color getColor(int index) {
return appointments![index].background;
}
}
You must call the notifier of the CalendarDataSource
when the datasource collection is modified to reflect the changes on UI that is an appointment added to the datasource or removed from the datasource.
events.dataSource.clear();
events.notifyListeners(CalendarDataSourceAction.reset, null);
Datasource manipulation
Whenever the datasource changes, to notify the datasource action (add, remove, and reset) through notify listener. In the following example, the appointment and resource are added, removed, and replaced and notifyListeners is called in onPressed callback of the FloatingActionButton.
Add Action
When dynamically adding appointments to a data source, we must notify the data source for the add action.
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
floatingActionButton: FloatingActionButton(
child: const Text('Add appointment'),
onPressed: () {
final Appointment app = Appointment(
startTime: _controller.displayDate!,
endTime:
_controller.displayDate!.add(const Duration(hours: 2)),
subject: 'Add Appointment',
color: Colors.pink);
_events?.appointments!.add(app);
_events?.notifyListeners(
CalendarDataSourceAction.add, <Appointment>[app]);
},
),
body: SfCalendar(
view: CalendarView.month,
controller: _controller,
dataSource: _events,
)),
);
}
Remove Action
When we remove appointments from a data source dynamically, we must notify the data source for the remove action.
final Appointment removeAppointment = _events?.appointments![0];
_events?.appointments!.remove(removeAppointment);
_events?.notifyListeners(CalendarDataSourceAction.remove,
<Appointment>[removeAppointment]);
Reset Action
When we replace appointments in a data source dynamically, we must notify the data source for the reset action.
_events?.appointments!.clear();
_events?.notifyListeners(
CalendarDataSourceAction.reset, _events!.appointments!);
Add Resource
When dynamically adding resource to a data source, we must notify the data source for add resource.
final CalendarResource resource = CalendarResource(
displayName: 'Sophia',
color: Colors.red,
id: '00045',
);
_events!.resources!.add(resource);
_events!.notifyListeners(CalendarDataSourceAction.addResource,
<CalendarResource>[resource]);
Remove Resource
When we remove resource from a data source dynamically, we must notify the data source for remove resource.
final CalendarResource resource = _events!.resources![0];
_events!.resources!.remove(resource);
_events!.notifyListeners(
CalendarDataSourceAction.removeResource,
<CalendarResource>[resource]);
Reset Resource
When we replace resource in a data source dynamically, we must notify the data source for reset resource.
final List<CalendarResource> collection =
<CalendarResource>[];
collection.add(CalendarResource(
displayName: "Sophia", id: '00045', color: Colors.green));
_events!.resources!.clear();
_events!.resources!.addAll(collection);
_events!.notifyListeners(
CalendarDataSourceAction.resetResource, collection);
Creating business objects
You can create a custom class Meeting
with mandatory fields from
, and to
.
class Meeting {
Meeting({this.eventName = '', required this.from, required this.to, required this.background, this.isAllDay = false});
String eventName;
DateTime from;
DateTime to;
Color background;
bool isAllDay;
}
You can map those properties of Meeting
class with our calendar widget by using the CalendarDataSource
override methods properties.
class MeetingDataSource extends CalendarDataSource {
MeetingDataSource(List<Meeting> source){
appointments = source;
}
@override
DateTime getStartTime(int index) {
return appointments![index].from;
}
@override
DateTime getEndTime(int index) {
return appointments![index].to;
}
@override
bool isAllDay(int index) {
return appointments![index].isAllDay;
}
@override
String getSubject(int index) {
return appointments![index].eventName;
}
@override
String getStartTimeZone(int index) {
return appointments![index].startTimeZone;
}
@override
String getEndTimeZone(int index) {
return appointments![index].endTimeZone;
}
@override
Color getColor(int index) {
return appointments![index].background;
}
}
You can schedule meetings for a day by setting From
and To
of Meeting class. Create meetings of type List<Meeting>
and assign those appointments collection Meetings to the appointments property of CalendarDataSource
.
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Container(
child: SfCalendar(
view: CalendarView.week,
dataSource: _getCalendarDataSource(),
),
),
),
);
}
MeetingDataSource _getCalendarDataSource() {
List<Meeting> meetings = <Meeting>[];
meetings.add(Meeting(
eventName: 'meeting',
from: DateTime(2019, 12, 18, 10),
to: DateTime(2019, 12, 18, 12),
background: Colors.green,
isAllDay: false));
return MeetingDataSource(meetings);
}
Get the business object data
The event data can be achieved in the custom business object type by overriding the convertAppointmentToObject() method from the CalendarDataSource
.
class _DataSource extends CalendarDataSource<_Meeting> {
_DataSource(List<_Meeting> source) {
appointments = source;
}
@override
DateTime getStartTime(int index) {
return appointments![index].from as DateTime;
}
@override
DateTime getEndTime(int index) {
return appointments![index].to as DateTime;
}
@override
String getSubject(int index) {
return appointments![index].content as String;
}
@override
Color getColor(int index) {
return appointments![index].background as Color;
}
@override
Meeting convertAppointmentToObject(
_Meeting customData, Appointment appointment) {
return Meeting(
from: appointment.startTime,
to: appointment.endTime,
content: appointment.subject,
background: appointment.color,
isAllDay: appointment.isAllDay);
}
}
class Meeting {
Meeting({this.content = '', required this.from, required this.to, required this.background, this.isAllDay = false});
String content;
DateTime from;
DateTime to;
Color background;
bool isAllDay;
}
NOTE
- This method must be implemented to get the data with business object type when drag and drop and appointment resizing enabled.
Spanned appointments
Spanned Appointment is an appointment, which lasts more than 24 hours. It does not block out time slots in SfCalendar, it will render in All-Day appointment panel
exclusively.
MeetingDataSource _getCalendarDataSource() {
List<Meeting> meetings = <Meeting>[];
meetings.add(Meeting(
eventName: 'meeting',
from: DateTime(2019, 11, 03, 10),
to: DateTime(2019, 11, 05, 12),
background: Colors.blue));
return MeetingDataSource(meetings);
}
All day appointment
All-Day appointment is an appointment which is scheduled for a whole day. It can be set by using the isAllDay property in the Appointment
.
_AppointmentDataSource _getCalendarDataSource() {
List<Appointment> appointments = <Appointment>[];
appointments.add(Appointment(
startTime: DateTime.now(),
endTime: DateTime.now().add(Duration(minutes: 10)),
subject: 'Meeting',
color: Colors.blue,
isAllDay: true,
));
return _AppointmentDataSource(appointments);
}
NOTE
- Appointment which lasts through an entire day (exact 24 hours) will be considered as all day appointment without setting the IsAllDay property. For example, 06/12/2019 12:00AM to 06/12/2019 12:00AM.
Recurrence appointment
Recurring appointment on a daily, weekly, monthly, or yearly interval. Recurring appointments can be created by setting the recurrenceRule property in Appointment
.
Recurrence rule
The recurrenceRule
is a string value (RRULE) that contains the details of the recurrence appointments such as repeat type - daily/weekly/monthly/yearly, how many times it needs to be repeated, the interval duration, also the time period to render the appointment, and more. The recurrenceRule
has the following properties and based on this property value, the recurrence appointments are rendered in the SfCalendar widget with its respective time period.
PropertyName | Purpose |
---|---|
FREQ | Maintains the Repeat type value of the appointment. (Example: Daily, Weekly, Monthly, Yearly, Every week day) Example: FREQ=DAILY;INTERVAL=1 |
INTERVAL | Maintains the interval value of the appointments. For example, when you create the daily appointment at an interval of 2, the appointments are rendered on the days Monday, Wednesday, and Friday. (Creates the appointment on all days by leaving the interval of one day gap) Example: FREQ=DAILY;INTERVAL=1 |
COUNT | It holds the appointment’s count value. For example, when the recurrence appointment count value is 10, it means 10 appointments are created in the recurrence series. Example: FREQ=DAILY;INTERVAL=1;COUNT=10 |
UNTIL | This property is used to store the recurrence end date value. For example, when you set the end date of the appointment as 6/30/2020, the UNTIL property holds the end date value when the recurrence ends. Example: FREQ=DAILY;INTERVAL=1;UNTIL=20200827T183000Z. The T separates the date portion from the time of day portion. Z denotes the UTC timezone for the date time value. |
BYDAY | It holds the “DAY” values of an appointment to render.For example, when you create the weekly appointment, select the day(s) from the day options (Monday/Tuesday/Wednesday/Thursday/Friday/Saturday/Sunday). When Monday is selected, the first two letters of the selected day “MO” is stored in the “BYDAY” property. When you select multiple days, the values are separated by commas. Example: FREQ=WEEKLY;INTERVAL=1;BYDAY=MO,WE;COUNT=10 |
BYMONTHDAY | This property is used to store the date value of the Month while creating the Month recurrence appointment. For example, when you create a Monthly recurrence appointment in the date 3, it means the BYMONTHDAY holds the value 3 and creates the appointment on 3rd day of every month. Example: FREQ=MONTHLY;BYMONTHDAY=3;INTERVAL=1;COUNT=10 |
BYMONTH | This property is used to store the index value of the selected Month while creating the yearly appointments. For example, when you create the yearly appointment in the Month June, it means the index value for June month is 6 and it is stored in the BYMONTH field. The appointment is created on every 6th month of a year. Example: FREQ=YEARLY;BYMONTHDAY=16;BYMONTH=6;INTERVAL=1;COUNT=10 |
BYSETPOS | This property is used to store the index value of the week. For example, when you create the monthly appointment in second week of the month, the index value of the second week (2) is stored in BYSETPOS. Example: FREQ=MONTHLY;BYDAY=MO;BYSETPOS=2;UNTIL=20200810T183000Z . If the property value is set to -1 and -2, the appointment will be added to the last week and second last week of the month. |
Adding recurrence appointment
Calendar appointment recurrenceRule is used to populate the required recurring appointment collection in a specific pattern. RRULE can be directly set to the recurrenceRule
property of Appointment
.
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Container(
child: SfCalendar(
view: CalendarView.week,
dataSource: _getCalendarDataSource(),
),
),
),
);
}
_AppointmentDataSource _getCalendarDataSource() {
List<Appointment> appointments = <Appointment>[];
appointments.add(Appointment(
startTime: DateTime(2019, 12, 16, 10),
endTime: DateTime(2019, 12, 16, 12),
subject: 'Meeting',
color: Colors.blue,
recurrenceRule: 'FREQ=DAILY;INTERVAL=2;COUNT=10'));
return _AppointmentDataSource(appointments);
}
class _AppointmentDataSource extends CalendarDataSource {
_AppointmentDataSource(List<Appointment> source) {
appointments = source;
}
}
Recurrence appointments on last day of month
To create recurring appointments on the last day of the month, use BYMONTHDAY=-1 in the flutter event calendar.
@override
Widget build(BuildContext context) {
return Scaffold(
body: SfCalendar(
view: CalendarView.month,
dataSource: _getCalendarDataSource(),
monthViewSettings: const MonthViewSettings(
appointmentDisplayMode: MonthAppointmentDisplayMode.appointment),
));
}
}
DataSource _getCalendarDataSource() {
final List<Appointment> appointments = <Appointment>[];
appointments.add(Appointment(
startTime: DateTime(2022, 2, 27, 9),
endTime: DateTime(2022, 2, 27, 10),
subject: 'Last day of month',
color: Colors.purple,
recurrenceRule: 'FREQ=MONTHLY;BYMONTHDAY=-1;INTERVAL=1;COUNT=10'));
return DataSource(appointments);
}
class DataSource extends CalendarDataSource {
DataSource(List<Appointment> source) {
appointments = source;
}
}
Creating custom recurrence appointment
For creating custom recurrence appointment, you need to create a custom class Meeting
with mandatory fields from
, to
, and recurrenceRule
.
class Meeting {
Meeting(
{this.eventName = '',
required this.from,
required this.to,
required this.background,
this.isAllDay = false,
this.recurrenceRule});
String eventName;
DateTime from;
DateTime to;
Color background;
bool isAllDay;
String? recurrenceRule;
}
You can map those properties of Meeting
class with our calendar widget by using CalendarDataSource
.
class MeetingDataSource extends CalendarDataSource {
MeetingDataSource(List<Meeting> source){
appointments = source;
}
@override
DateTime getStartTime(int index) {
return appointments![index].from;
}
@override
DateTime getEndTime(int index) {
return appointments![index].to;
}
@override
bool isAllDay(int index) {
return appointments![index].isAllDay;
}
@override
String getSubject(int index) {
return appointments![index].eventName;
}
@override
Color getColor(int index) {
return appointments![index].background;
}
@override
String getRecurrenceRule(int index) {
return appointments![index].recurrenceRule;
}
}
You can schedule recurring meetings for daily, weekly, monthly, or yearly interval by setting recurrenceRule
of Meeting
class. Create meetings of type List
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Container(
child: SfCalendar(
view: CalendarView.week,
dataSource: _getCalendarDataSource(),
),
),
),
);
}
MeetingDataSource _getCalendarDataSource() {
List<Meeting> meetings = <Meeting>[];
meetings.add(Meeting(
eventName: 'meeting',
from: DateTime(2019, 12, 18, 10),
to: DateTime(2019, 12, 18, 12),
background: Colors.green,
isAllDay: false,
recurrenceRule: 'FREQ=WEEKLY;BYDAY=MO,WE,FR;INTERVAL=1;COUNT=10'));
return MeetingDataSource(meetings);
}}
class MeetingDataSource extends CalendarDataSource {
MeetingDataSource(List<Meeting> source){
appointments = source;
}
@override
DateTime getStartTime(int index) {
return appointments![index].from;
}
@override
DateTime getEndTime(int index) {
return appointments![index].to;
}
@override
bool isAllDay(int index) {
return appointments![index].isAllDay;
}
@override
String getSubject(int index) {
return appointments![index].eventName;
}
@override
Color getColor(int index) {
return appointments![index].background;
}
@override
String getRecurrenceRule(int index) {
return appointments![index].recurrenceRule;
}
}
class Meeting {
Meeting({this.eventName = '',
required this.from,
required this.to,
required this.background,
this.isAllDay = false,
this.recurrenceRule});
String eventName;
DateTime from;
DateTime to;
Color background;
bool isAllDay;
String? recurrenceRule;
}
How to get the Recurrence editor field values from RRULE?
You can get the Recurrence properties form RRULE
by using the parseRRule method from calendar.
DateTime dateTime = DateTime(2020, 03, 15);
RecurrenceProperties recurrenceProperties =
SfCalendar.parseRRule('FREQ=DAILY;INTERVAL=1;COUNT=1', dateTime);
Recurrence properties retrieved from above method,
recurrenceProperties.recurrenceType = RecurrenceType.daily;
recurrenceProperties.interval = 1;
recurrenceProperties.recurrenceCount = 3;
recurrenceProperties.recurrenceRange = RecurrenceRange.count;
How to get the recurrence dates from RRULE?
You can get the occurrences date time list of recurring appointment from RRULE using the getRecurrenceDateTimeCollection method of SfCalendar.
DateTime dateTime = DateTime(2020, 03, 15);
List<DateTime> dateCollection = SfCalendar.getRecurrenceDateTimeCollection(
'FREQ=DAILY;INTERVAL=1;COUNT=3', dateTime);
The following occurrence dates can be retrieved from the given RRULE:
var date0 = 3/15/2019;
var date1 = 3/16/2019;
var date2 = 3/16/2019;
Recurrence pattern exceptions
You can delete or change any recurrence pattern appointment by handling exception dates and exception appointments to that recurring appointment.
Recurrence exception dates
You can delete any occurrence appointment, which exception from the recurrence pattern appointment by adding exception dates to the recurring appointment.
Recurrence exception appointment
You can also change any occurrence appointment, which exception from recurrence pattern appointment by adding the recurrence exception appointment to the calendar dataSource
.
Create recurrence exceptions for calendar appointment
You can add the recurrence exception appointments and recurrence exception dates to Appointment
or remove them from Appointment
by using its recurrenceExceptionDates property.
Delete occurrence from recurrence pattern appointment or adding exception dates to recurrence pattern appointment
You can delete any of occurrence, which is an exception from the recurrence pattern appointment by using the recurrenceExceptionDates
property of Appointment
. The deleted occurrence date will be considered as recurrence exception dates.
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Container(
child: SfCalendar(
view: CalendarView.week,
dataSource: _getCalendarDataSource(),
),
),
),
);
}
_AppointmentDataSource _getCalendarDataSource() {
List<Appointment> appointments = <Appointment>[];
DateTime exceptionDate = DateTime(2019, 12, 20);
appointments.add(Appointment(
startTime: DateTime(2019, 12, 16, 10),
endTime: DateTime(2019, 12, 16, 12),
subject: 'Occurs daily',
color: Colors.red,
recurrenceRule: 'FREQ=DAILY;COUNT=20',
recurrenceExceptionDates: <DateTime>[exceptionDate]));
return _AppointmentDataSource(appointments);
}
class _AppointmentDataSource extends CalendarDataSource {
_AppointmentDataSource(List<Appointment> source) {
appointments = source;
}
}
NOTE
- Exception dates should be Universal Time Coordinates (UTC) time zone.
Create recurrence exceptions for custom appointment
You can add the recurrence exception appointments and recurrence exception dates to the CustomAppointment or remove them from CustomAppointment, you can create a custom class Meeting
with mandatory field RecurrenceExceptionDates
.
Delete occurrence from custom recurrence pattern appointment or adding exception dates to custom recurrence pattern appointment
You can delete any occurrence, which is an exception from the recurrence pattern appointment by using the getRecurrenceExceptionDates
override method of CalendarDataSource
, which is used to map the exception dates to the calendar recurrence appointment. The deleted occurrence date will be considered as recurrence exception dates.
To add the exception dates in the recurrence series of custom appointment, add the recurrenceExceptionDates
property to custom class Meeting.
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Container(
child: SfCalendar(
view: CalendarView.week,
dataSource: _getCalendarDataSource(),
),
),
),
);
}
MeetingDataSource _getCalendarDataSource() {
List<Meeting> meetings = <Meeting>[];
DateTime exceptionDate = DateTime(2019, 12, 24);
meetings.add(Meeting(
eventName: 'meeting',
from: DateTime(2019, 12, 18, 10),
to: DateTime(2019, 12, 18, 12),
background: Colors.green,
isAllDay: false,
recurrenceRule: 'FREQ=DAILY;COUNT=20',
exceptionDates: <DateTime>[exceptionDate]));
return MeetingDataSource(meetings);
}
class MeetingDataSource extends CalendarDataSource {
MeetingDataSource(List<Meeting> source) {
appointments = source;
}
@override
DateTime getStartTime(int index) {
return appointments![index].from;
}
@override
DateTime getEndTime(int index) {
return appointments![index].to;
}
@override
bool isAllDay(int index) {
return appointments![index].isAllDay;
}
@override
String getSubject(int index) {
return appointments![index].eventName;
}
@override
Color getColor(int index) {
return appointments![index].background;
}
@override
String getRecurrenceRule(int index) {
return appointments![index].recurrenceRule;
}
@override
List<DateTime> getRecurrenceExceptionDates(int index) {
return appointments![index].exceptionDates;
}
}
class Meeting {
Meeting(
{this.eventName = '',
required this.from,
required this.to,
required this.background,
this.isAllDay = false,
this.recurrenceRule,
this.exceptionDates});
String eventName;
DateTime from;
DateTime to;
Color background;
bool isAllDay;
String? recurrenceRule;
List<DateTime>? exceptionDates;
}
NOTE
- Exception dates should be Universal Time Coordinates (UTC) time zone.
Add exception appointment to the recurrence series
Add an exception appointment that is changed or modified occurrence of the recurrence pattern appointment to the dateSource
of the SfCalendar
. To add a changed occurrence, ensure to set the RecurrenceId of that occurrence, and add the date of that occurrence to the RecurrenceExceptionDates of recurrence pattern appointment. The RecurrenceId
of the changed occurrence should hold the exact recurrence pattern appointment Id. We can get the type of appointment from the appointmentType property.
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Container(
child: SfCalendar(
view: CalendarView.week,
dataSource: _getDataSource(),
),
),
),
);
}
AppointmentDataSource _getDataSource() {
final List<Appointment> appointments = <Appointment>[];
final DateTime exceptionDate = DateTime(2021, 04, 20);
final Appointment recurrenceAppointment = Appointment(
startTime: DateTime(2021, 04, 12, 10),
endTime: DateTime(2021, 04, 12, 12),
subject: 'Scrum meeting',
id: '01',
recurrenceRule: 'FREQ=DAILY;INTERVAL=1;COUNT=10',
color: Colors.purple,
recurrenceExceptionDates: <DateTime>[exceptionDate],
);
appointments.add(recurrenceAppointment);
final Appointment exceptionAppointment = Appointment(
startTime: exceptionDate.add(const Duration(hours: 14)),
endTime: exceptionDate.add(const Duration(hours: 15)),
subject: 'Meeting',
id: '02',
color: Colors.pinkAccent,
recurrenceId: recurrenceAppointment.id);
appointments.add(exceptionAppointment);
return AppointmentDataSource(appointments);
}
NOTE
- The RecurrenceId of the changed occurrence should hold the exact recurrence pattern appointment Id.
- The exception appointment should be a normal appointment, and should not be created as recurring appointment, since its occurrence is from recurrence pattern.
- The exception recurrence appointment does not have the RecurrenceRule, so for an exception appointment, it will be reset to empty.
Appearance customization
The Calendar appointment text style can be customized by using the appointmentTextStyle property of the calendar.
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Container(
child: SfCalendar(
view: CalendarView.day,
dataSource: _getCalendarDataSource(),
appointmentTextStyle: TextStyle(
fontSize: 25,
color: Color(0xFFd89cf6),
letterSpacing: 5,
fontWeight: FontWeight.bold),
),
),
),
);
}
Appointment time format
You can customize the displaying time format in the appointment widget in the month agenda view and schedule view of calendar by specifying the appointmentTimeTextFormat property of the SfCalendar.
@override
Widget build(BuildContext context) {
return SfCalendar(
view: CalendarView.month,
dataSource: _calendarDataSource,
appointmentTimeTextFormat: 'HH:mm',
monthViewSettings: MonthViewSettings(
showAgenda: true
),
);
}
Appointment helper
Get visible appointments
You can get the list of visible appointments by using the getVisibleAppointments method available in the Calendar data source.
@override
initState() {
_calendarController = CalendarController();
_dataSource = _getCalendarDataSource();
super.initState();
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: SfCalendar(
view: CalendarView.month,
controller: _calendarController,
dataSource: _dataSource,
onViewChanged: (ViewChangedDetails details) {
List<DateTime> dates = details.visibleDates;
String calendarTimeZone = '';
List<Object> appointment = _dataSource.getVisibleAppointments(
dates[0], calendarTimeZone,
dates[(details.visibleDates.length) - 1]);
},
),
),
);
}
}
NOTE
- The
startTime
specifies the starting date from which the appointments should be obtained.
Get occurrence appointment
Gets an occurrence at the specified date within a series of recurring appointments by using the getOccurrenceAppointment.
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: SfCalendar(
view: CalendarView.month,
controller: _calendarController,
dataSource: _dataSource,
onTap: (CalendarTapDetails details) {
final DateTime? date = details.date;
final Appointment? occurrenceAppointment =
_dataSource.getOccurrenceAppointment(recurrenceApp, date!, '');
},
),
),
);
}
NOTE
- If there is no appointment occurring on the date specified, null is returned.
- The
patternAppointment
is required for the start appointment in a recurrence series, from which the occurrence appointments are cloned with the pattern appointment characteristics.- The
date
is required for the occurrence appointment.
Get pattern appointment
Gets the pattern appointment for the specified occurrence by using the getPatternAppointment.
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: SfCalendar(
view: CalendarView.month,
controller: _calendarController,
dataSource: _dataSource,
onTap: (CalendarTapDetails details) {
if (details.appointments!.isNotEmpty &&
details.appointments != null) {
final dynamic occurrenceAppointment = details.appointments![0];
final Appointment? patternAppointment =
_dataSource.getPatternAppointment(occurrenceAppointment, '')
as Appointment?;
}
},
),
),
);
}
NOTE
- The
occurrenceAppointment
is necessary in order to receive the Pattern appointment.
See also
- How to design and configure your appointment editor in event calendar widget Flutter
- How to get appointment details from the OnTap event of the Flutter event calendar
- How to style the appointment in the Flutter event calendar (SfCalendar)
- How to exclude the dates from recurrence appointments in the Flutter event calendar (SfCalendar)
- How to add recurring appointments until the specified date in the Flutter event calendar (SfCalendar)
- How to add the appointments to the Fire base database using appointment editor in the Flutter event calendar (SfCalendar)
- How to work with the Fire base database and the Flutter event calendar (SfCalendar) for appointments
- How to add google calendar events to the Flutter event calendar (SfCalendar)
- How to add additional attributes in events in the Flutter event calendar (SfCalendar)
- How to add the appointments using the onTap callback in the Flutter event calendar (SfCalendar)
- How to set the arbitrary height to appointments in the Flutter event calendar (SfCalendar)
- How to get the recurrence date collection in the Flutter event calendar (SfCalendar)
- How to get the recurrence properties from RRULE in the Flutter calendar
- How to update blackout dates using onViewChanged callback in the Flutter calendar
- How to use navigation drawer for view switching in the Flutter calendar
- How to show the tapped appointment details on another page in the Flutter event calendar
- How to load appointments On-Demand in Flutter Calendar
- How to load the google calendar events to the Flutter Calendar (SfCalendar) in iOS
- How to perform the CRUD operations in Flutter Calendar using Fire base database
- How to add the appointments to Fire store Database using Flutter Calendar
- How to perform the CRUD operations in Flutter Calendar using Fire store database