FlutterCalendarWidget

A calendar control on Flutter can be customized to look as you want. Making the address

introduce

I wrote an open source library for the Flutter calendar. Recently, I added some features, refactoring the code, and some performance optimizations. (The previous code is really ****, no state frame, but also a variety of nested code)

The sample

Calendar supports Web preview: Click here for preview







The main function

  • Support the Gregorian calendar, lunar calendar, solar terms, traditional festivals, common holidays
  • Date range Settings. The maximum date range supported by default is 1971.01-2055.12
  • Disable the setting of date range. For example, you can click the date in a certain range and turn off the date outside the range
  • Supports single or multiple callbacks. Multiple callbacks that exceed the specified number of callbacks are supported.
  • Jump to a specified date, default support animation switch
  • Custom calendar items, support the way of combining widgets and drawing with canvas
  • Customize the WeekBar at the top
  • Depending on the actual scenario, you can add additional custom data to Item to achieve various additional functions. For example, the implementation of the progress bar style calendar, the realization of the calendar of various marks
  • Supports weekly view display
  • Display and switch linkage between month and week views

The recent changes

[1.0.0] – 2019/10/10

  • Refactoring calendar code for performance optimization
  • Create the Configuration class and place the configuration information here
  • Introduce provider state management, avoid various nested transfers of data, and implement local refreshes
  • Realize the weekly view and the linkage between the weekly view and the monthly view. Use IndexStack to wrap the two weekly and monthly views. Switch to changing the index of IndexStack
  • DateModel adds isCurrentMonth to draw the month view to mask days that are not in the current month. IsCurrentMonth is false for days preceding or following the current month.
  • Click item to refresh, and control the refresh range: refresh only two items, the current item and the previous item, in radio mode. In multi-select mode, only the selected item is refreshed.
  • Data initialization of DateModel, some properties lazily loaded using get method

[0.0.1] – 2019/5/19.

  • Support the Gregorian calendar, lunar calendar, solar terms, traditional festivals, common holidays
  • Date range Settings. The maximum date range supported by default is 1971.01-2055.12
  • Disable the setting of date range. For example, you can click the date in a certain range and turn off the date outside the range
  • Supports single or multiple callbacks. Multiple callbacks that exceed the specified number of callbacks are supported.
  • Jump to a specified date, default support animation switch
  • Custom calendar items, support the way of combining widgets and drawing with canvas
  • Customize the WeekBar at the top
  • You can add custom extra data to an Item for various additional functions. Like implementing a progress bar style calendar

use

Add dependencies to pubspec.yaml:

flutter_custom_calendar:
    git:
      url: https://github.com/LXD312569496/flutter_custom_calendar.git
Copy the code

With the introduction of flutter_CUSTOM_calendar, you can use the CalendarViewWidget and configure the CalendarController.

import 'package:flutter_custom_calendar/flutter_custom_calendar.dart';

CalendarViewWidget({@required this.calendarController, this.boxDecoration});
Copy the code
  • BoxDecoration is used to configure the overall background
  • Use the CalendarController to configure some data, and you can use the CalendarController to perform operations or event listening, such as scrolling to the next month, retrieving the currently selected items, and so on.

Configuration CalendarController

Below are some of the attributes in CalendarController that support custom configuration. If no value is specified, the default value will be used. (The Configuration is now done in the Controller, and the configured data will be divided into the Configuration class.)

The meaning of configuration includes three aspects.

  • One is to display the relevant data needed for the calendar,
  • One is the configuration of a custom UI that displays the calendar,
  • One is to configure calendar listening events.
// Constructor CalendarController({int selectMode = Constants.MODE_SINGLE_SELECT, int showMode = Constants.MODE_SHOW_ONLY_MONTH, bool expandStatus =true,
      DayWidgetBuilder dayWidgetBuilder = defaultCustomDayWidget,
      WeekBarItemWidgetBuilder weekBarItemWidgetBuilder = defaultWeekBarWidget,
      int minYear = 1971,
      int maxYear = 2055,
      int minYearMonth = 1,
      int maxYearMonth = 12,
      int nowYear = -1,
      int nowMonth = -1,
      int minSelectYear = 1971,
      int minSelectMonth = 1,
      int minSelectDay = 1,
      int maxSelectYear = 2055,
      int maxSelectMonth = 12,
      int maxSelectDay = 30,
      Set<DateTime> selectedDateTimeList = EMPTY_SET,
      DateModel selectDateModel,
      int maxMultiSelectCount = 9999,
      double verticalSpacing = 10,
      bool enableExpand = true,
      Map<DateModel, Object> extraDataMap = EMPTY_MAP})

Copy the code

Data configuration

attribute meaning The default value
selectMode Select mode: single or multiple options The default is radio

static const int MODE_SINGLE_SELECT = 1;

static const int MODE_MULTI_SELECT = 2;
showMode Display mode The default is to show only the monthly view

static const int MODE_SHOW_ONLY_MONTH=1; // Only monthly views are supported

static const int MODE_SHOW_ONLY_WEEK=2; // Only the weekly view is supported

static const int MODE_SHOW_WEEK_AND_MONTH=3; // Support switching between monthly and weekly views
minYear The minimum year displayed on the calendar 1971
maxYear The maximum year displayed on the calendar 2055
minYearMonth The month of the smallest year displayed on the calendar 1
maxYearMonth The month of the maximum year displayed on the calendar 12
nowYear The calendar displays the current year – 1
nowMonth Calendar displays the current month – 1
minSelectYear The minimum year you can select 1971
minSelectMonth Month of the smallest year you can select 1
minSelectDay The date of the smallest month you can choose 1
maxSelectYear Maximum year you can select 2055
maxSelectMonth Month of the maximum year you can select 12
maxSelectDay The date of the maximum month you can choose 30, note: cannot exceed the total number of days in the corresponding month
selectedDateList The date selected for multiple selections Default is null Set, Set selectedDateList = new Set()
selectDateModel Current option for radio selection The default is empty
maxMultiSelectCount Multiple choices, maximum number of choices hhh
extraDataMap Customize additional data * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

Configuration related to UI drawing

attribute meaning The default value
weekBarItemWidgetBuilder Create the weekbar at the top The default styles
dayWidgetBuilder Create calendar Item The default styles
verticalSpacing The vertical spacing between calendar items The default 10
boxDecoration Overall background setting
itemSize The side length of each item The default is screen width /7

Configuration of event listening

methods meaning The default value
void addMonthChangeListener(OnMonthChange listener) Month switch event
void addOnCalendarSelectListener(OnCalendarSelect listener) I’m gonna go ahead and select the event
void addOnMultiSelectOutOfRangeListener(OnMultiSelectOutOfRange listener) Multiple selection exceeds the specified range
void addOnMultiSelectOutOfSizeListener(OnMultiSelectOutOfSize listener) The number of multiple selections exceeds the limit
void addExpandChangeListener(ValueChanged expandChange) Listen for the calendar to expand and shrink

Use controller to control calendar switching, support configuration animation

methods meaning The default value
Future previousPage() Sliding to the previous page will automatically slide to the previous month or week based on the current expansion status. Returns false if it is already on the first page without the previous one, or true in other cases
Future nextPage() Sliding to the next page will automatically slide to the next month or week, depending on the current state of expansion. Returns false if there is no next page on the last page, true otherwise
void moveToCalendar(int year, int month, int day, {bool needAnimation = false,Duration duration = const Duration(milliseconds: 500),Curve curve = Curves.ease}) To specified date
void moveToNextYear() Switch to the next year
void moveToPreviousYear() Switch to the previous year
void moveToNextMonth() Switch to the next month
void moveToPreviousMonth() Switch to the previous month
void toggleExpandStatus() Switching state

Use the Controller to get some data information about the calendar

methods meaning The default value
DateTime getCurrentMonth() Gets the current month
Set getMultiSelectCalendar() Gets the selected date, multiple options
DateModel getSingleSelectCalendar() Gets the selected date, single

How do I customize the UI

This includes custom weekbars, custom calendar items, and DefaultXXXWidget.

Just inherit the corresponding Base class, implement the corresponding method, and then just implement the corresponding Builder method when configuring the Controller.

// Support custom drawing DayWidgetBuilder; // Create calendar item WeekBarItemWidgetBuilder WeekBarItemWidgetBuilder; // Create the weekbar at the topCopy the code

Custom WeekBar

Inherit BaseWeekBar and override getWeekBarItem(index). You can implement it however you want, just return a Widget.

class DefaultWeekBar extends BaseWeekBar { const DefaultWeekBar({Key key}) : super(key: key); @override Widget getWeekBarItem(int index) {/** * Custom Widget */returnnew Container( height: 40, alignment: Alignment.center, child: new Text( Constants.WEEK_LIST[index], style: topWeekTextStyle, ), ); }}Copy the code

Custom calendar Item:

Two methods are provided: one is to create a widget by combining widgets, and the other is to draw items by customization using Canvas. Finally, you just need to configure in the CalendarController’s construction parameters.

  • Inherit the BaseCombineDayWidget, override getNormalWidget(DateModel DateModel) and getSelectedWidget(DateModel DateModel), and return the corresponding widget.
class DefaultCombineDayWidget extends BaseCombineDayWidget { DefaultCombineDayWidget(DateModel dateModel) : super(dateModel); @override Widget getNormalWidget(DateModel DateModel) {// Implement default UI} @override Widget getSelectedWidget(DateModel) DateModel) {// Draw the selected UI}}Copy the code
  • Inherit the BaseCustomDayWidget and override the drawNormal and drawSelected methods to draw the Item on the Canvas.
class DefaultCustomDayWidget extends BaseCustomDayWidget { DefaultCustomDayWidget(DateModel dateModel) : super(dateModel); @override void drawNormal(DateModel DateModel, Canvas Canvas, Size Size) {override void drawNormal(DateModel, Canvas Canvas, Size Size) { canvas, size); } @override void drawSelected(DateModel dateModel, Canvas canvas, // Draw the selected UI defaultDrawSelected(dateModel, canvas, Size); }}Copy the code

Customize additional data extraData according to actual scenarios

Customize progress bar data for each item

< dateModel, int> progressMap = {datemodel.fromdatetime (temp.add(Duration(days: 1))): 0, DateModel.fromDateTime(temp.add(Duration(days: 2))): 20, DateModel.fromDateTime(temp.add(Duration(days: 3))): 40, DateModel.fromDateTime(temp.add(Duration(days: 4))): 60, DateModel.fromDateTime(temp.add(Duration(days: 5))): 80, DateModel.fromDateTime(temp.add(Duration(days: 6))): 100, }; // Add extraDataMap to CalendarController(extraDataMap: Int progress = datemodel.extradata; progressMap = datemodel.extradata;Copy the code

Customize various tags

// External processing of each dateModel tag Map< dateModel, String> customExtraData = { DateModel.fromDateTime(DateTime.now().add(Duration(days: -1))):"False",
    DateModel.fromDateTime(DateTime.now().add(Duration(days: -2))): "Swim",
    DateModel.fromDateTime(DateTime.now().add(Duration(days: -3))): "Things",
    DateModel.fromDateTime(DateTime.now().add(Duration(days: -4))): "Class",
    DateModel.fromDateTime(DateTime.now().add(Duration(days: -5))): "False",
    DateModel.fromDateTime(DateTime.now().add(Duration(days: -6))): "Swim",
    DateModel.fromDateTime(DateTime.now().add(Duration(days: 2))): "Swim",
    DateModel.fromDateTime(DateTime.now().add(Duration(days: 3))): "Things",
    DateModel.fromDateTime(DateTime.now().add(Duration(days: 4))): "Class",
    DateModel.fromDateTime(DateTime.now().add(Duration(days: 5))): "False",
    DateModel.fromDateTime(DateTime.now().add(Duration(days: 6))): "Swim",
    DateModel.fromDateTime(DateTime.now().add(Duration(days: 7))): "Things",
    DateModel.fromDateTime(DateTime.now().add(Duration(days: 8))): "Class"}; // Add extraDataMap to CalendarController(extraDataMap: // When drawing the DayWidget, you can get the desired data directly from the dateModel extraData object. String data = datemodel. extraData;Copy the code

DateModel entity class

The entity class DateModel for dates used in the calendar has the following attributes. When you customize a DayWidget, you can draw the UI based on its properties.

attribute meaning type The default value
year year int
month in int
day The date of int The default is 1
lunarYear Chinese New Year int
lunarMonth The lunar month int
lunarDay According to the lunar calendar date int
lunarString Lunar string String
solarTerm 24 solar terms String
gregorianFestival gregorianFestival String
traditionFestival Traditional Lunar Festivals String
isCurrentDay Is it today bool false
isLeapYear Is it a leap year bool false
isWeekend Is it the weekend bool false
isInRange Whether it is within the range, for example, it can implement the function of setting gray outside a certain range bool false
isSelected Is selected to implement some tag or selection function bool false
extraData Custom additional data Object The default is empty
methods meaning
DateTime getDateTime() Convert DateModel to DateTime
DateModel fromDateTime(DateTime dateTime) Create the corresponding model based on DateTime and initialize the information of lunar and traditional festivals
bool operator ==(Object other) Override the == method to determine if two dateModel are the same day