introduce

Recently I wrote a demo, using the calendar aspect of things, and then implement it, the last plan to encapsulate it, can be directly used in the future.

A reference to an open source calendar library for Android github.com/huanghaibin… In fact, the implementation idea is the same, can use canvas to draw the calendar.

The project address of the Flutter Calendar: github.com/LXD31256949…

The sample

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

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
  • 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.

Below are some of the attributes in CalendarController that support custom configuration. If no value is specified, the default value will be used.

// MODE_SINGLE_SELECT, MODE_MULTI_SELECT int selectMode; // The calendar displays the minimum year and the maximum year int minYear; int maxYear; // The calendar displays the month of the smallest year, the month of the largest year int minYearMonth; int maxYearMonth; // Calendar displays the current year and month int nowYear; int nowMonth; // Optional range Settings, such as select Int minSelectYear; int minSelectMonth; int minSelectDay; int maxSelectYear; int maxSelectMonth; int maxSelectDay; Set<DateModel> selectedDateList = new Set(); // The selected date, used for multi-select DateModel selectDateModel; // Current selection, used for single int maxMultiSelectCount; <DateTime, Object> extraDataMap = new Map(); // Custom additional data // various events callback OnMonthChange monthChange; OnCalendarSelect calendarSelect; // Select the event OnMultiSelectOutOfRange; // multiSelectOutOfSize multiSelectOutOfSize; DayWidgetBuilder; DayWidgetBuilder; // Create calendar item WeekBarItemWidgetBuilder WeekBarItemWidgetBuilder; Constructor CalendarController({int selectMode = Constants.MODE_SINGLE_SELECT, 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, Map<DateTime, Object> extraDataMap = EMPTY_MAP})Copy the code

Add listening events using controller

Such as month switch events, click select events.

Void addMonthChangeListener(OnMonthChange Listener) {this.monthChange = listener; } / / click select listening void addOnCalendarSelectListener (OnCalendarSelect listener) {enclosing calendarSelect = listener; } / / alternative is beyond the scope specified void addOnMultiSelectOutOfRangeListener (OnMultiSelectOutOfRange listener) {enclosing multiSelectOutOfRange = listener; } / / alternative beyond limit the number of void addOnMultiSelectOutOfSizeListener (OnMultiSelectOutOfSize listener) {enclosing multiSelectOutOfSize = listener; }Copy the code

Use controller to control calendar switching, support configuration animation

Void moveToCalendar(int year, int Month, int day, {bool needAnimation =false, Duration duration = const Duration(milliseconds: 500), Curve curve = Curves.ease}); // Switch to next year void moveToNextYear(); Void moveToPreviousYear(); // Switch to the next month, void moveToNextMonth(); Void moveToPreviousMonth();Copy the code

Use the Controller to get some data information about the calendar

// Get the current month DateTime getCurrentMonth(); // Get the selected date, multiselect Set<DateModel> getMultiSelectCalendar(); // Get the selected date, call DateModel getSingleSelectCalendar();Copy the code

Custom 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

DateModel entity class

The entity class DateModel for dates used in the calendar has the following attributes.

/** * class DateModel {int year; int month; int day = 1; int lunarYear; int lunarMonth; int lunarDay; String lunarString; // Lunar String String solarTerm; //24 solar term String gregorianFestival; // Gregorian calendar String traditionFestival; // Traditional Lunar Festivals bool isCurrentDay; // whether today bool isLeapYear; // whether is leap year bool isWeekend; Int leapMonth; // Whether the leap month Object extraData; // Custom additional data bool isInRange =false; Bool isSelected; bool isSelected; bool isSelected; // Whether it is selected to implement some tag or select function @override StringtoString() {
    return 'DateModel{year: $year, month: $month, day: $day}'; } // If it is a leap month, return leap month // convert to DateTime format DateTimegetDateTime() {
    return new DateTime(year, month, day);
  }
  //根据DateTime创建对应的model,并初始化农历和传统节日等信息
  static DateModel fromDateTime(DateTime dateTime) {
    DateModel dateModel = new DateModel()
      ..year = dateTime.year
      ..month = dateTime.month
      ..day = dateTime.day;
    LunarUtil.setupLunarCalendar(dateModel);
    returndateModel; } @override bool operator ==(Object other) => identical(this, other) || other is DateModel && runtimeType == other.runtimeType && year == other.year && month == other.month && day ==  other.day; @override int gethashCode => year.hashCode ^ month.hashCode ^ day.hashCode;
}
Copy the code

TODO LIST

  • Optimize code implementation
  • Support blocking specific days
  • Continue to write several different styles of Demo
  • Support for weekly view
  • Support animation to switch between weekly view and monthly view