Flutter上的一個日曆控件,能夠定製成本身想要的樣子。Github地址git
以前寫了一個Flutter日曆的開源庫,最近增長了一些功能,而且對代碼進行了一下重構,再搞了下性能優化。(以前的代碼寫得真的是****,沒搞狀態框架,還各類嵌套代碼)github
日曆支持web預覽:點擊此處進入預覽web
在pubspec.yaml添加依賴:canvas
flutter_custom_calendar:
git:
url: https://github.com/LXD312569496/flutter_custom_calendar.git
複製代碼
引入flutter_custom_calendar,就可使用CalendarViewWidget,配置CalendarController就能夠了。性能優化
import 'package:flutter_custom_calendar/flutter_custom_calendar.dart';
CalendarViewWidget({@required this.calendarController, this.boxDecoration});
複製代碼
下面是CalendarController中一些支持自定義配置的屬性。不配置的話,會有對應的默認值。(配置如今都是在controller這裏進行配置的,內部會將配置的數據抽成Configuration類)bash
配置的含義主要包括了3個方面的配置。框架
//構造函數
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})
複製代碼
屬性 | 含義 | 默認值 |
---|---|---|
selectMode | 選擇模式,表示單選或者多選 | 默認是單選 static const int MODE_SINGLE_SELECT = 1; static const int MODE_MULTI_SELECT = 2; |
showMode | 展現模式 | 默認是隻展現月視圖 static const int MODE_SHOW_ONLY_MONTH=1;//僅支持月視圖 static const int MODE_SHOW_ONLY_WEEK=2;//僅支持星期視圖 static const int MODE_SHOW_WEEK_AND_MONTH=3;//支持月和星期視圖切換 |
minYear | 日曆顯示的最小年份 | 1971 |
maxYear | 日曆顯示的最大年份 | 2055 |
minYearMonth | 日曆顯示的最小年份的月份 | 1 |
maxYearMonth | 日曆顯示的最大年份的月份 | 12 |
nowYear | 日曆顯示的當前的年份 | -1 |
nowMonth | 日曆顯示的當前的月份 | -1 |
minSelectYear | 能夠選擇的最小年份 | 1971 |
minSelectMonth | 能夠選擇的最小年份的月份 | 1 |
minSelectDay | 能夠選擇的最小月份的日子 | 1 |
maxSelectYear | 能夠選擇的最大年份 | 2055 |
maxSelectMonth | 能夠選擇的最大年份的月份 | 12 |
maxSelectDay | 能夠選擇的最大月份的日子 | 30,注意:不能超過對應月份的總天數 |
selectedDateList | 被選中的日期,用於多選 | 默認爲空Set, Set selectedDateList = new Set() |
selectDateModel | 當前選擇項,用於單選 | 默認爲空 |
maxMultiSelectCount | 多選,最多選多少個 | hhh |
extraDataMap | 自定義額外的數據 | 默認爲空Map,Map<DateTime, Object> extraDataMap = new Map() |
屬性 | 含義 | 默認值 |
---|---|---|
weekBarItemWidgetBuilder | 建立頂部的weekbar | 默認樣式 |
dayWidgetBuilder | 建立日曆item | 默認樣式 |
verticalSpacing | 日曆item之間的豎直方向間距 | 默認10 |
boxDecoration | 總體的背景設置 | |
itemSize | 每一個item的邊長 | 默認是屏幕寬度/7 |
方法 | 含義 | 默認值 |
---|---|---|
void addMonthChangeListener(OnMonthChange listener) | 月份切換事件 | |
void addOnCalendarSelectListener(OnCalendarSelect listener) | 點擊選擇事件 | |
void addOnMultiSelectOutOfRangeListener(OnMultiSelectOutOfRange listener) | 多選超出指定範圍 | |
void addOnMultiSelectOutOfSizeListener(OnMultiSelectOutOfSize listener) | 多選超出限制個數 | |
void addExpandChangeListener(ValueChanged expandChange) | 監聽日曆的展開收縮狀態 |
方法 | 含義 | 默認值 |
---|---|---|
Future previousPage() | 滑動到上一個頁面,會自動根據當前的展開狀態,滑動到上一個月或者上一個星期。若是已經在第一個頁面,沒有上一個頁面,就會返回false,其餘狀況返回true | |
Future nextPage() | 滑動到下一個頁面,會自動根據當前的展開狀態,滑動到下一個月或者下一個星期。若是已經在最後一個頁面,沒有下一個頁面,就會返回false,其餘狀況返回true | |
void moveToCalendar(int year, int month, int day, {bool needAnimation = false,Duration duration = const Duration(milliseconds: 500),Curve curve = Curves.ease}) | 到指定日期 | |
void moveToNextYear() | 切換到下一年 | |
void moveToPreviousYear() | 切換到上一年 | |
void moveToNextMonth() | 切換到下一個月份 | |
void moveToPreviousMonth() | 切換到上一個月份 | |
void toggleExpandStatus() | 切換展開狀態 |
方法 | 含義 | 默認值 |
---|---|---|
DateTime getCurrentMonth() | 獲取當前的月份 | |
Set getMultiSelectCalendar() | 獲取被選中的日期,多選 | |
DateModel getSingleSelectCalendar() | 獲取被選中的日期,單選 |
包括自定義WeekBar、自定義日曆Item,默認使用的都是DefaultXXXWidget。ide
只要繼承對應的Base類,實現相應的方法,而後只須要在配置Controller的時候,實現相應的Builder方法就能夠了。函數
//支持自定義繪製
DayWidgetBuilder dayWidgetBuilder; //建立日曆item
WeekBarItemWidgetBuilder weekBarItemWidgetBuilder; //建立頂部的weekbar
複製代碼
繼承BaseWeekBar,重寫getWeekBarItem(index)方法就能夠。隨便你怎麼實現,只須要返回一個Widget就能夠了。性能
class DefaultWeekBar extends BaseWeekBar {
const DefaultWeekBar({Key key}) : super(key: key);
@override
Widget getWeekBarItem(int index) {
/**
* 自定義Widget
*/
return new Container(
height: 40,
alignment: Alignment.center,
child: new Text(
Constants.WEEK_LIST[index],
style: topWeekTextStyle,
),
);
}
}
複製代碼
提供兩種方法,一種是利用組合widget的方式來建立,一種是利用Canvas來自定義繪製Item。最後只須要在CalendarController的構造參數中進行配置就能夠了。
class DefaultCombineDayWidget extends BaseCombineDayWidget {
DefaultCombineDayWidget(DateModel dateModel) : super(dateModel);
@override
Widget getNormalWidget(DateModel dateModel) {
//實現默認狀態下的UI
}
@override
Widget getSelectedWidget(DateModel dateModel) {
//繪製被選中的UI
}
}
複製代碼
class DefaultCustomDayWidget extends BaseCustomDayWidget {
DefaultCustomDayWidget(DateModel dateModel) : super(dateModel);
@override
void drawNormal(DateModel dateModel, Canvas canvas, Size size) {
//實現默認狀態下的UI
defaultDrawNormal(dateModel, canvas, size);
}
@override
void drawSelected(DateModel dateModel, Canvas canvas, Size size) {
//繪製被選中的UI
defaultDrawSelected(dateModel, canvas, size);
}
}
複製代碼
//外部處理每一個dateModel所對應的進度
Map<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,
};
//建立CalendarController對象的時候,將extraDataMap賦值就好了
new CalendarController(
extraDataMap: progressMap)
//繪製DayWidget的時候,能夠直接從dateModel的extraData對象中拿到想要的數據
int progress = dateModel.extraData;
複製代碼
//外部處理每一個dateModel所對應的標記
Map<DateModel, String> customExtraData = {
DateModel.fromDateTime(DateTime.now().add(Duration(days: -1))): "假",
DateModel.fromDateTime(DateTime.now().add(Duration(days: -2))): "遊",
DateModel.fromDateTime(DateTime.now().add(Duration(days: -3))): "事",
DateModel.fromDateTime(DateTime.now().add(Duration(days: -4))): "班",
DateModel.fromDateTime(DateTime.now().add(Duration(days: -5))): "假",
DateModel.fromDateTime(DateTime.now().add(Duration(days: -6))): "遊",
DateModel.fromDateTime(DateTime.now().add(Duration(days: 2))): "遊",
DateModel.fromDateTime(DateTime.now().add(Duration(days: 3))): "事",
DateModel.fromDateTime(DateTime.now().add(Duration(days: 4))): "班",
DateModel.fromDateTime(DateTime.now().add(Duration(days: 5))): "假",
DateModel.fromDateTime(DateTime.now().add(Duration(days: 6))): "遊",
DateModel.fromDateTime(DateTime.now().add(Duration(days: 7))): "事",
DateModel.fromDateTime(DateTime.now().add(Duration(days: 8))): "班",
};
//建立CalendarController對象的時候,將extraDataMap賦值就好了
new CalendarController(
extraDataMap: customExtraData)
//繪製DayWidget的時候,能夠直接從dateModel的extraData對象中拿到想要的數據
String data = dateModel.extraData;
複製代碼
日曆所用的日期的實體類DateModel,有下面這些屬性。能夠在自定義繪製DayWidget的時候,根據相應的屬性,進行判斷後,繪製相應的UI。
屬性 | 含義 | 類型 | 默認值 |
---|---|---|---|
year | 年份 | int | |
month | 月份 | int | |
day | 日期 | int | 默認爲1 |
lunarYear | 農曆年份 | int | |
lunarMonth | 農曆月份 | int | |
lunarDay | 農曆日期 | int | |
lunarString | 農曆字符串 | String | |
solarTerm | 24節氣 | String | |
gregorianFestival | gregorianFestival | String | |
traditionFestival | 傳統農曆節日 | String | |
isCurrentDay | 是不是今天 | bool | false |
isLeapYear | 是不是閏年 | bool | false |
isWeekend | 是不是週末 | bool | false |
isInRange | 是否在範圍內,好比能夠實如今某個範圍外,設置置灰的功能 | bool | false |
isSelected | 是否被選中,用來實現一些標記或者選擇功能 | bool | false |
extraData | 自定義的額外數據 | Object | 默認爲空 |
方法 | 含義 |
---|---|
DateTime getDateTime() | 將DateModel轉化成DateTime |
DateModel fromDateTime(DateTime dateTime) | 根據DateTime建立對應的model,並初始化農曆和傳統節日等信息 |
bool operator ==(Object other) | 重寫==方法,能夠判斷兩個dateModel是不是同一天 |