创建configuration类,将配置的信息放到这里

引入provider状态管理,避免深层嵌套传递信息
周视图和月视图,联动
增加日志输出类LogUtil,方便查看调试
增加example例子
性能优化
develop
xiaodong 5 years ago
parent b26999d210
commit 6dcf7c21a2

@ -20,7 +20,7 @@ Flutter上的一个日历控件可以定制成自己想要的样子。
## 近期修改
### [1.0.0] - 2019/9/22
* 重构日历的代码
* 重构日历的代码,进行性能优化
* 创建configuration类将配置的信息放到这里
* 引入provider状态管理,避免深层嵌套传递信息
* 实现周视图,并实现周视图和月视图之间的联动
@ -55,8 +55,9 @@ CalendarViewWidget({@required this.calendarController, this.boxDecoration});
* boxDecoration用来配置整体的背景
* 利用CalendarController来配置一些数据并且可以通过CalendarController进行一些操作或者事件监听比如滚动到下一个月获取当前被选中的Item等等。
## 配置CalendarController
下面是CalendarController中一些支持自定义配置的属性。不配置的话会有对应的默认值。
配置都是在controller里面进行配置的。。考虑到之前版本所以才这样搞
个人觉得配置的含义主要包括了3个方面的配置。
* 一个是显示日历所需要的相关数据,
@ -67,6 +68,7 @@ CalendarViewWidget({@required this.calendarController, this.boxDecoration});
//构造函数
CalendarController(
{int selectMode = Constants.MODE_SINGLE_SELECT,
bool expandStatus = true,
DayWidgetBuilder dayWidgetBuilder = defaultCustomDayWidget,
WeekBarItemWidgetBuilder weekBarItemWidgetBuilder = defaultWeekBarWidget,
int minYear = 1971,
@ -84,11 +86,13 @@ CalendarViewWidget({@required this.calendarController, this.boxDecoration});
Set<DateTime> selectedDateTimeList = EMPTY_SET,
DateModel selectDateModel,
int maxMultiSelectCount = 9999,
Map<DateTime, Object> extraDataMap = EMPTY_MAP})
double verticalSpacing = 10,
bool enableExpand = true,
Map<DateModel, Object> extraDataMap = EMPTY_MAP})
```
数据方面的配置
### 数据方面的配置
属性 | 含义 | 默认值
:-: | :-: | :-:
@ -111,7 +115,7 @@ maxMultiSelectCount | 多选,最多选多少个| hhh
extraDataMap | 自定义额外的数据| 默认为空MapMap<DateTime, Object> extraDataMap = new Map()
UI绘制相关的配置
### UI绘制相关的配置
属性 | 含义 | 默认值
:-: | :-: | :-:
@ -119,23 +123,23 @@ weekBarItemWidgetBuilder | 创建顶部的weekbar | 默认样式
dayWidgetBuilder | 创建日历item | 默认样式
事件监听的配置
### 事件监听的配置
方法 | 含义 | 默认值
:-: | :-: | :-:
void addMonthChangeListener(OnMonthChange listener) | 月份切换事件 | 默认为空
void addOnCalendarSelectListener(OnCalendarSelect listener) | 点击选择事件 | 默认为空
void addOnMultiSelectOutOfRangeListener(OnMultiSelectOutOfRange listener) | 多选超出指定范围 | 默认为空
void addOnMultiSelectOutOfSizeListener(OnMultiSelectOutOfSize listener) | 多选超出限制个数 | 默认为空
void addMonthChangeListener(OnMonthChange listener) | 月份切换事件 |
void addOnCalendarSelectListener(OnCalendarSelect listener) | 点击选择事件 |
void addOnMultiSelectOutOfRangeListener(OnMultiSelectOutOfRange listener) | 多选超出指定范围 |
void addOnMultiSelectOutOfSizeListener(OnMultiSelectOutOfSize listener) | 多选超出限制个数 |
void addExpandChangeListener(ValueChanged<bool> expandChange)|监听日历的展开收缩状态|
### 利用controller来控制日历的切换支持配置动画
## 利用controller来控制日历的切换支持配置动画
方法 | 含义 | 默认值
:-: | :-: | :-:
Future<bool> previousPage()|滑动到上一个页面会自动根据当前的展开状态滑动到上一个月或者上一个星期。如果已经在第一个页面没有上一个页面就会返回false其他情况返回true|
Future<bool> 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 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()|切换到下一个月份|
@ -143,7 +147,7 @@ void moveToPreviousMonth()|切换到上一个月份|
void toggleExpandStatus()|切换展开状态|
### 利用controller来获取日历的一些数据信息
## 利用controller来获取日历的一些数据信息
方法 | 含义 | 默认值
:-: | :-: | :-:
@ -152,7 +156,7 @@ Set<DateModel> getMultiSelectCalendar()|获取被选中的日期,多选|
DateModel getSingleSelectCalendar()|获取被选中的日期,单选|
### 如何自定义UI
## 如何自定义UI
包括自定义WeekBar、自定义日历Item默认使用的都是DefaultXXXWidget。
@ -271,7 +275,7 @@ class DefaultCustomDayWidget extends BaseCustomDayWidget {
### DateModel实体类
## DateModel实体类
日历所用的日期的实体类DateModel有下面这些属性。可以在自定义绘制DayWidget的时候根据相应的属性进行判断后绘制相应的UI。
属性|含义|类型|默认值
@ -286,12 +290,12 @@ lunarString|农历字符串|String|
solarTerm|24节气|String|
gregorianFestival|gregorianFestival|String|
traditionFestival|传统农历节日|String|
isCurrentDay|是否是今天|bool|
isLeapYear|是否是闰年|bool|
isWeekend|是否是周末|bool|
isCurrentDay|是否是今天|bool|false
isLeapYear|是否是闰年|bool|false
isWeekend|是否是周末|bool|false
isInRange|是否在范围内,比如可以实现在某个范围外,设置置灰的功能|bool|false
isSelected|是否被选中,用来实现一些标记或者选择功能|bool|false
extraData|自定义的额外数据|Object
extraData|自定义的额外数据|Object|默认为空
方法|含义|

@ -23,8 +23,12 @@ class _DefaultStylePageState extends State<DefaultStylePage> {
@override
void initState() {
DateTime now = DateTime.now();
controller = new CalendarController(
minYear: 2019, minYearMonth: 8, maxYear: 2019, maxYearMonth: 9);
minYear: now.year,
minYearMonth: now.month - 2,
maxYear: now.year,
maxYearMonth: now.month + 1);
controller.addMonthChangeListener(
(year, month) {

@ -1,17 +1,23 @@
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'custom_sign_page.dart';
import 'custom_style_page.dart';
import 'default_style_page.dart';
import 'multi_select_style_page.dart';
import 'progress_style_page.dart';
void main() => runApp(MyApp());
void main(){
// debugProfileBuildsEnabled=true;
// debugProfilePaintsEnabled=true;
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
// checkerboardOffscreenLayers: true, // 使saveLayer
routes: <String, WidgetBuilder>{
"/default": (context) => DefaultStylePage(
title: "默认风格+单选",

@ -1,6 +1,20 @@
# Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile
packages:
archive:
dependency: transitive
description:
name: archive
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.0.10"
args:
dependency: transitive
description:
name: args
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.5.2"
async:
dependency: transitive
description:
@ -29,6 +43,20 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.14.11"
convert:
dependency: transitive
description:
name: convert
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.1.1"
crypto:
dependency: transitive
description:
name: crypto
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.1.3"
cupertino_icons:
dependency: "direct main"
description:
@ -53,6 +81,13 @@ packages:
description: flutter
source: sdk
version: "0.0.0"
image:
dependency: transitive
description:
name: image
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.1.4"
matcher:
dependency: transitive
description:
@ -81,6 +116,13 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.8.0+1"
petitparser:
dependency: transitive
description:
name: petitparser
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.4.0"
provider:
dependency: transitive
description:
@ -163,5 +205,12 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.0.8"
xml:
dependency: transitive
description:
name: xml
url: "https://pub.flutter-io.cn"
source: hosted
version: "3.5.0"
sdks:
dart: ">=2.2.2 <3.0.0"
dart: ">=2.4.0 <3.0.0"

@ -0,0 +1,26 @@
import 'package:flutter_custom_calendar/model/date_model.dart';
/**
*
*/
class CacheData {
//
CacheData._();
static CacheData _instance;
static CacheData get instance => _instance;
Map<DateModel, List<DateModel>> monthListCache = Map();
Map<DateModel, List<DateModel>> weekListCache = Map();
static CacheData getInstance() {
if (_instance == null) {
_instance = new CacheData._();
}
return _instance;
}
}

@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_custom_calendar/configuration.dart';
import 'package:flutter_custom_calendar/model/date_model.dart';
import 'package:flutter_custom_calendar/utils/LogUtil.dart';
import 'package:flutter_custom_calendar/utils/date_util.dart';
import 'package:flutter_custom_calendar/widget/month_view.dart';
/**
@ -12,8 +13,17 @@ import 'package:flutter_custom_calendar/widget/month_view.dart';
class CalendarProvider extends ChangeNotifier {
Set<DateModel> selectedDateList = new Set(); //,
DateModel _selectDateModel; //
DateModel lastClickDateModel; //
MultiSelectItemContainerState lastClickItemState;
ItemContainerState lastClickItemState;
DateModel _lastClickDateModel;
DateModel get lastClickDateModel =>
_lastClickDateModel; //
set lastClickDateModel(DateModel value) {
_lastClickDateModel = value;
print("lastClickDateModel:$lastClickDateModel");
}
DateModel get selectDateModel => _selectDateModel;
@ -22,7 +32,49 @@ class CalendarProvider extends ChangeNotifier {
LogUtil.log(
TAG: this.runtimeType,
message: "selectDateModel change:${selectDateModel}");
notifyListeners();
// notifyListeners();
}
//lastClickDateModelindex
int get weekPageIndex {
//index
DateModel dateModel = lastClickDateModel;
DateTime firstWeek = calendarConfiguration.weekList[0].getDateTime();
int index = 0;
for (int i = 0; i < calendarConfiguration.weekList.length; i++) {
DateTime nextWeek = firstWeek.add(Duration(days: 7));
if (dateModel.getDateTime().isBefore(nextWeek)) {
index = i;
break;
} else {
firstWeek = nextWeek;
index++;
}
}
print("lastClickDateModel:$lastClickDateModel,weekPageIndex:$index");
return index;
}
//lastClickDateModelindex
int get monthPageIndex {
//index
DateModel dateModel = lastClickDateModel;
int index = 0;
for (int i = 0; i < calendarConfiguration.monthList.length - 1; i++) {
DateTime preMonth = calendarConfiguration.monthList[i].getDateTime();
DateTime nextMonth = calendarConfiguration.monthList[i + 1].getDateTime();
if (!dateModel.getDateTime().isBefore(preMonth) &&
!dateModel.getDateTime().isAfter(nextMonth)) {
index = i;
break;
} else {
index++;
}
}
print("lastClickDateModel:$lastClickDateModel,monthPageIndex:$index");
return index + 1;
}
ValueNotifier<bool> expandStatus = ValueNotifier(true); //
@ -43,7 +95,15 @@ class CalendarProvider extends ChangeNotifier {
//lastClickDateModelitem
this.lastClickDateModel = selectDateModel != null
? selectDateModel
: DateModel.fromDateTime(DateTime.now());
: DateModel.fromDateTime(DateTime.now())
..day = 15;
// expandStatus.addListener(() {
// print("1111");
// if (expandStatus.value == false) {
// calendarConfiguration.weekController.jumpToPage(weekPageIndex);
// }
// });
}
//退

@ -9,8 +9,11 @@ class CalendarConfiguration {
//,MODE_SINGLE_SELECTMODE_MULTI_SELECT
int selectMode;
//
int showMode;
bool defaultExpandStatus; //,truefalse
bool enableExpand; //
bool enableExpand; //,truefalse
//
int minYear;
@ -42,6 +45,7 @@ class CalendarConfiguration {
*/
double verticalSpacing; //item10
BoxDecoration boxDecoration; //
double itemSize; ///7
//
DayWidgetBuilder dayWidgetBuilder; //item
@ -61,7 +65,7 @@ class CalendarConfiguration {
*/
List<DateModel> monthList = new List(); //list
List<DateModel> weekList = new List(); //list
PageController pageController; //controller
PageController monthController; //controller
PageController weekController; //controller
CalendarConfiguration(
@ -83,9 +87,10 @@ class CalendarConfiguration {
this.extraDataMap,
this.monthList,
this.weekList,
this.pageController,
this.monthController,
this.weekController,
this.verticalSpacing,
this.itemSize,
this.enableExpand,
bool defaultExpandStatus}) {
this.defaultExpandStatus = defaultExpandStatus;
@ -93,6 +98,6 @@ class CalendarConfiguration {
@override
String toString() {
return 'CalendarConfiguration{selectMode: $selectMode, expandStatus: $defaultExpandStatus, minYear: $minYear, maxYear: $maxYear, minYearMonth: $minYearMonth, maxYearMonth: $maxYearMonth, nowYear: $nowYear, nowMonth: $nowMonth, minSelectYear: $minSelectYear, minSelectMonth: $minSelectMonth, minSelectDay: $minSelectDay, maxSelectYear: $maxSelectYear, maxSelectMonth: $maxSelectMonth, maxSelectDay: $maxSelectDay, defaultSelectedDateList: $defaultSelectedDateList, maxMultiSelectCount: $maxMultiSelectCount, extraDataMap: $extraDataMap, monthList: $monthList, weekList: $weekList, pageController: $pageController, weekController: $weekController}';
return 'CalendarConfiguration{selectMode: $selectMode, expandStatus: $defaultExpandStatus, minYear: $minYear, maxYear: $maxYear, minYearMonth: $minYearMonth, maxYearMonth: $maxYearMonth, nowYear: $nowYear, nowMonth: $nowMonth, minSelectYear: $minSelectYear, minSelectMonth: $minSelectMonth, minSelectDay: $minSelectDay, maxSelectYear: $maxSelectYear, maxSelectMonth: $maxSelectMonth, maxSelectDay: $maxSelectDay, defaultSelectedDateList: $defaultSelectedDateList, maxMultiSelectCount: $maxMultiSelectCount, extraDataMap: $extraDataMap, monthList: $monthList, weekList: $weekList, monthController: $monthController, weekController: $weekController}';
}
}

@ -84,7 +84,7 @@ class CalendarController {
}
//pageController,initialPage
int initialPage;
int initialPage = 0;
int nowMonthIndex = 0;
monthList.clear();
for (int i = minYear; i <= maxYear; i++) {
@ -111,7 +111,8 @@ class CalendarController {
nowMonthIndex++;
}
}
this.monthController = new PageController(initialPage: initialPage);
this.monthController =
new PageController(initialPage: initialPage, keepPage: true);
LogUtil.log(
TAG: this.runtimeType,
message: "start:${DateModel.fromDateTime(DateTime(
@ -153,7 +154,7 @@ class CalendarController {
calendarConfiguration.monthList = monthList;
calendarConfiguration.weekList = weekList;
calendarConfiguration.pageController = monthController;
calendarConfiguration.monthController = monthController;
calendarConfiguration.weekController = weekController;
calendarConfiguration.dayWidgetBuilder = dayWidgetBuilder;
calendarConfiguration.weekBarItemWidgetBuilder = weekBarItemWidgetBuilder;
@ -200,22 +201,31 @@ class CalendarController {
Future<bool> previousPage() async {
if (calendarProvider.expandStatus.value == true) {
//
int currentIndex = monthController.page.toInt();
int currentIndex =
calendarProvider.calendarConfiguration.monthController.page.toInt();
if (currentIndex == 0) {
return false;
} else {
monthController.previousPage(
duration: DEFAULT_DURATION, curve: Curves.ease);
calendarProvider.calendarConfiguration.monthController
.previousPage(duration: DEFAULT_DURATION, curve: Curves.ease);
calendarProvider.calendarConfiguration.monthChange(
monthList[currentIndex].year, monthList[currentIndex].month);
DateModel temp = new DateModel();
temp.year = monthList[currentIndex].year;
temp.month = monthList[currentIndex].month;
temp.day = monthList[currentIndex].day + 14;
calendarProvider.lastClickDateModel = temp;
return true;
}
} else {
//
int currentIndex = weekController.page.toInt();
int currentIndex =
calendarProvider.calendarConfiguration.weekController.page.toInt();
if (currentIndex == 0) {
return false;
} else {
weekController.previousPage(
duration: DEFAULT_DURATION, curve: Curves.ease);
calendarProvider.calendarConfiguration.weekController
.previousPage(duration: DEFAULT_DURATION, curve: Curves.ease);
return true;
}
}
@ -229,21 +239,31 @@ class CalendarController {
Future<bool> nextPage() async {
if (calendarProvider.expandStatus.value == true) {
//
int currentIndex = monthController.page.toInt();
int currentIndex =
calendarProvider.calendarConfiguration.monthController.page.toInt();
if (monthList.length - 1 == currentIndex) {
return false;
} else {
monthController.nextPage(
duration: DEFAULT_DURATION, curve: Curves.ease);
calendarProvider.calendarConfiguration.monthController
.nextPage(duration: DEFAULT_DURATION, curve: Curves.ease);
calendarProvider.calendarConfiguration.monthChange(
monthList[currentIndex].year, monthList[currentIndex].month);
DateModel temp = new DateModel();
temp.year = monthList[currentIndex].year;
temp.month = monthList[currentIndex].month;
temp.day = monthList[currentIndex].day + 14;
calendarProvider.lastClickDateModel = temp;
return true;
}
} else {
//
int currentIndex = weekController.page.toInt();
int currentIndex =
calendarProvider.calendarConfiguration.weekController.page.toInt();
if (weekList.length - 1 == currentIndex) {
return false;
} else {
weekController.nextPage(duration: DEFAULT_DURATION, curve: Curves.ease);
calendarProvider.calendarConfiguration.weekController
.nextPage(duration: DEFAULT_DURATION, curve: Curves.ease);
return true;
}
}
@ -261,14 +281,16 @@ class CalendarController {
if (targetPage == -1) {
return;
}
if (monthController.hasClients == false) {
if (calendarProvider.calendarConfiguration.monthController.hasClients ==
false) {
return;
}
if (needAnimation) {
monthController.animateToPage(targetPage,
duration: duration, curve: curve);
calendarProvider.calendarConfiguration.monthController
.animateToPage(targetPage, duration: duration, curve: curve);
} else {
monthController.jumpToPage(targetPage);
calendarProvider.calendarConfiguration.monthController
.jumpToPage(targetPage);
}
} else {
DateModel dateModel = DateModel.fromDateTime(DateTime(year, month, 1));
@ -282,14 +304,16 @@ class CalendarController {
return;
}
}
if (weekController.hasClients == false) {
if (calendarProvider.calendarConfiguration.weekController.hasClients ==
false) {
return;
}
if (needAnimation) {
weekController.animateToPage(targetPage,
duration: duration, curve: curve);
calendarProvider.calendarConfiguration.weekController
.animateToPage(targetPage, duration: duration, curve: curve);
} else {
weekController.jumpToPage(targetPage);
calendarProvider.calendarConfiguration.weekController
.jumpToPage(targetPage);
}
}
}
@ -299,8 +323,11 @@ class CalendarController {
{bool needAnimation = false,
Duration duration = const Duration(milliseconds: 500),
Curve curve = Curves.ease}) {
DateTime targetDateTime =
monthList[monthController.page.toInt() + 12].getDateTime();
DateTime targetDateTime = monthList[calendarProvider
.calendarConfiguration.monthController.page
.toInt() +
12]
.getDateTime();
moveToCalendar(
targetDateTime.year, targetDateTime.month, targetDateTime.day,
needAnimation: needAnimation, duration: duration, curve: curve);
@ -311,8 +338,11 @@ class CalendarController {
{bool needAnimation = false,
Duration duration = const Duration(milliseconds: 500),
Curve curve = Curves.ease}) {
DateTime targetDateTime =
monthList[monthController.page.toInt() - 12].getDateTime();
DateTime targetDateTime = monthList[calendarProvider
.calendarConfiguration.monthController.page
.toInt() -
12]
.getDateTime();
moveToCalendar(
targetDateTime.year, targetDateTime.month, targetDateTime.day,
needAnimation: needAnimation, duration: duration, curve: curve);
@ -325,22 +355,33 @@ class CalendarController {
Curve curve = Curves.ease}) {
// indexweekController
if (calendarProvider.expandStatus.value == false) {
int currentMonth = weekList[weekController.page.toInt()].month;
for (int i = weekController.page.toInt(); i < weekList.length; i++) {
int currentMonth = weekList[calendarProvider
.calendarConfiguration.weekController.page
.toInt()]
.month;
for (int i = calendarProvider.calendarConfiguration.weekController.page
.toInt();
i < weekList.length;
i++) {
if (weekList[i].month != currentMonth) {
weekController.jumpToPage(i);
calendarProvider.calendarConfiguration.weekController.jumpToPage(i);
break;
}
}
return;
}
if ((monthController.page.toInt() + 1) >= monthList.length) {
if ((calendarProvider.calendarConfiguration.monthController.page.toInt() +
1) >=
monthList.length) {
LogUtil.log(TAG: this.runtimeType, message: "moveToNextMonth当前是最后一个月份");
return;
}
DateTime targetDateTime =
monthList[monthController.page.toInt() + 1].getDateTime();
DateTime targetDateTime = monthList[calendarProvider
.calendarConfiguration.monthController.page
.toInt() +
1]
.getDateTime();
moveToCalendar(
targetDateTime.year, targetDateTime.month, targetDateTime.day,
needAnimation: needAnimation, duration: duration, curve: curve);
@ -354,25 +395,32 @@ class CalendarController {
// indexweekController
if (calendarProvider.expandStatus.value == false) {
int currentMonth = weekList[weekController.page.toInt()].month;
for (int i = weekController.page.toInt(); i >= 0; i--) {
for (int i = calendarProvider.calendarConfiguration.weekController.page
.toInt();
i >= 0;
i--) {
if (weekList[i].month != currentMonth &&
weekList[i].isAfter(DateModel.fromDateTime(DateTime(
calendarConfiguration.minYear,
calendarConfiguration.minYearMonth)))) {
weekController.jumpToPage(i);
calendarProvider.calendarConfiguration.weekController.jumpToPage(i);
break;
}
}
return;
}
if ((monthController.page.toInt()) == 0) {
if ((calendarProvider.calendarConfiguration.monthController.page.toInt()) ==
0) {
LogUtil.log(
TAG: this.runtimeType, message: "moveToPreviousMonth当前是第一个月份");
return;
}
DateTime targetDateTime =
monthList[monthController.page.toInt() - 1].getDateTime();
DateTime targetDateTime = monthList[calendarProvider
.calendarConfiguration.monthController.page
.toInt() -
1]
.getDateTime();
moveToCalendar(
targetDateTime.year, targetDateTime.month, targetDateTime.day,
needAnimation: needAnimation, duration: duration, curve: curve);
@ -398,7 +446,7 @@ class CalendarController {
* weekBar
*/
Widget defaultWeekBarWidget() {
return DefaultWeekBar();
return const DefaultWeekBar();
}
/**

@ -11,6 +11,13 @@ class DateModel {
List<int> lunar = List(3);
// List<int> get lunar {
// if (lunar?.isNotEmpty == false) {
// return lunar;
// }
//// return LunarUtil.solarToLunar(year, month, day);
// }
//
String get lunarString {
if (solarTerm.isNotEmpty) {

@ -1,3 +1,4 @@
import 'dart:developer';
import 'dart:math';
import 'package:flutter_custom_calendar/model/date_model.dart';
@ -114,6 +115,7 @@ class DateUtil {
{DateModel minSelectDate,
DateModel maxSelectDate,
Map<DateModel, Object> extraDataMap}) {
print('initCalendarForMonthView start');
weekStart = DateTime.monday;
//
int mPreDiff = getIndexOfFirstDayInMonth(new DateTime(year, month));
@ -125,6 +127,7 @@ class DateUtil {
message:
"initCalendarForMonthView:$year$month月,有$monthDayCount天,第一天的index为${mPreDiff}");
List<DateModel> result = new List();
int size = 42;
@ -162,7 +165,7 @@ class DateUtil {
dateModel.isInRange = false;
}
//model
if (extraDataMap != null && extraDataMap.isNotEmpty) {
if (extraDataMap?.isNotEmpty == true) {
if (extraDataMap.containsKey(dateModel)) {
dateModel.extraData = extraDataMap[dateModel];
}
@ -171,6 +174,8 @@ class DateUtil {
result.add(dateModel);
}
print('initCalendarForMonthView end');
return result;
}
@ -200,7 +205,6 @@ class DateUtil {
{DateModel minSelectDate,
DateModel maxSelectDate,
Map<DateModel, Object> extraDataMap}) {
LogUtil.log(TAG: "DateUtil", message: "initCalendarForWeekView");
List<DateModel> items = List();
int weekDay = currentDate.weekday;
@ -226,7 +230,7 @@ class DateUtil {
}
//model
if (extraDataMap != null && extraDataMap.isNotEmpty) {
if (extraDataMap?.isNotEmpty == true) {
if (extraDataMap.containsKey(dateModel)) {
dateModel.extraData = extraDataMap[dateModel];
}

@ -6,9 +6,9 @@ import 'package:flutter_custom_calendar/model/date_model.dart';
* canvasitem
*/
abstract class BaseCustomDayWidget extends StatelessWidget {
DateModel dateModel;
final DateModel dateModel;
BaseCustomDayWidget(
const BaseCustomDayWidget(
this.dateModel,
);

@ -1,8 +1,10 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_custom_calendar/calendar_provider.dart';
import 'package:flutter_custom_calendar/controller.dart';
import 'package:flutter_custom_calendar/model/date_model.dart';
import 'package:flutter_custom_calendar/utils/LogUtil.dart';
import 'package:flutter_custom_calendar/utils/date_util.dart';
import 'package:flutter_custom_calendar/widget/month_view_pager.dart';
import 'package:flutter_custom_calendar/widget/week_view_pager.dart';
import 'package:provider/provider.dart';
@ -66,16 +68,41 @@ class CalendarContainerState extends State<CalendarContainer>
CalendarProvider calendarProvider;
var state = CrossFadeState.showFirst;
List<Widget> widgets;
int index = 0;
@override
void initState() {
calendarProvider = Provider.of<CalendarProvider>(context, listen: false);
expand = calendarProvider.expandStatus.value;
widgets = [
const MonthViewPager(),
const WeekViewPager(),
];
//
if (calendarProvider.calendarConfiguration.enableExpand == true) {
calendarProvider.expandStatus.addListener(() {
setState(() {
expand = !expand;
expand = calendarProvider.expandStatus.value;
state = (state == CrossFadeState.showSecond
? CrossFadeState.showFirst
: CrossFadeState.showSecond);
if (expand) {
index = 0;
//
calendarProvider.calendarConfiguration.weekController
.jumpToPage(calendarProvider.monthPageIndex);
} else {
index = 1;
//
calendarProvider.calendarConfiguration.weekController
.jumpToPage(calendarProvider.weekPageIndex);
}
});
});
}
@ -90,28 +117,60 @@ class CalendarContainerState extends State<CalendarContainer>
Widget build(BuildContext context) {
LogUtil.log(TAG: this.runtimeType, message: "CalendarContainerState build");
//,,:a horizontal viewport was given an unlimited amount of I/flutter ( 6759): vertical space in which to expand.
itemHeight = MediaQuery.of(context).size.width / 7;
itemHeight = calendarProvider.calendarConfiguration.itemSize ??
MediaQuery.of(context).size.width / 7;
totalHeight = itemHeight * 6 + 10 * (6 - 1);
// return Container(
// child: new Column(
// children: <Widget>[
// /**
// * constsetStateview
// */
// calendarProvider.calendarConfiguration.weekBarItemWidgetBuilder(),
// AnimatedContainer(
// duration: Duration(milliseconds: 200),
// width: itemHeight * 7,
// height: expand ? totalHeight : itemHeight,
// child: expand
// ? Container(
// height: totalHeight,
// child: MonthViewPager(),
// )
// : Container(
// height: itemHeight,
// child: WeekViewPager(),
// ),
// ),
// ],
// ),
// );
// return Container(
// child: AnimatedCrossFade(
// firstChild: Container(height: totalHeight, child: MonthViewPager()),
// secondChild: Container(height: itemHeight, child: WeekViewPager()),
// crossFadeState: state,
// duration: Duration(milliseconds: 500)),
// );
return Container(
width: itemHeight * 7,
child: new Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
/**
* constsetStateview
*/
calendarProvider.calendarConfiguration.weekBarItemWidgetBuilder(),
AnimatedContainer(
duration: Duration(milliseconds: 200),
duration: Duration(milliseconds: 500),
height: expand ? totalHeight : itemHeight,
child: expand
? Container(
height: totalHeight,
child: MonthViewPager(),
)
: Container(
height: itemHeight,
child: WeekViewPager(),
),
),
child: IndexedStack(
// overflow: Overflow.visible,
index: index,
children: widgets,
)),
],
),
);

@ -8,7 +8,7 @@ import 'package:flutter_custom_calendar/style/style.dart';
*/
class DefaultCustomDayWidget extends BaseCustomDayWidget {
DefaultCustomDayWidget(DateModel dateModel) : super(dateModel);
const DefaultCustomDayWidget(DateModel dateModel) : super(dateModel);
@override
void drawNormal(DateModel dateModel, Canvas canvas, Size size) {

@ -1,4 +1,8 @@
import 'dart:developer';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_custom_calendar/cache_data.dart';
import 'package:flutter_custom_calendar/calendar_provider.dart';
import 'package:flutter_custom_calendar/configuration.dart';
import 'package:flutter_custom_calendar/constants/constants.dart';
@ -15,25 +19,21 @@ class MonthView extends StatefulWidget {
final int month;
final int day;
final DateModel minSelectDate;
final DateModel maxSelectDate;
final Map<DateModel, Object> extraDataMap; //
final CalendarConfiguration configuration;
const MonthView({
@required this.year,
@required this.month,
this.day,
this.minSelectDate,
this.maxSelectDate,
this.extraDataMap,
this.configuration,
});
@override
_MonthViewState createState() => _MonthViewState();
}
class _MonthViewState extends State<MonthView> {
class _MonthViewState extends State<MonthView>
with AutomaticKeepAliveClientMixin {
List<DateModel> items;
int lineCount;
@ -42,21 +42,46 @@ class _MonthViewState extends State<MonthView> {
double totalHeight;
double mainSpacing = 10;
DateModel minSelectDate;
DateModel maxSelectDate;
Map<DateModel, Object> extraDataMap; //
@override
void initState() {
super.initState();
minSelectDate = DateModel.fromDateTime(DateTime(
widget.configuration.minSelectYear,
widget.configuration.minSelectMonth,
widget.configuration.minSelectDay));
maxSelectDate = DateModel.fromDateTime(DateTime(
widget.configuration.maxSelectYear,
widget.configuration.maxSelectMonth,
widget.configuration.maxSelectDay));
extraDataMap = widget.configuration.extraDataMap;
DateModel firstDayOfMonth =
DateModel.fromDateTime(DateTime(widget.year, widget.month, 1));
if (CacheData.getInstance().monthListCache[firstDayOfMonth]?.isNotEmpty ==
true) {
LogUtil.log(TAG: this.runtimeType, message: "缓存中有数据");
items = CacheData.getInstance().monthListCache[firstDayOfMonth];
} else {
LogUtil.log(TAG: this.runtimeType, message: "缓存中无数据");
items = DateUtil.initCalendarForMonthView(
widget.year, widget.month, DateTime.now(), DateTime.sunday,
minSelectDate: widget.minSelectDate,
maxSelectDate: widget.maxSelectDate,
extraDataMap: widget.extraDataMap);
minSelectDate: minSelectDate,
maxSelectDate: maxSelectDate,
extraDataMap: extraDataMap);
CacheData.getInstance().monthListCache[firstDayOfMonth] = items;
}
lineCount = DateUtil.getMonthViewLineCount(widget.year, widget.month);
}
@override
Widget build(BuildContext context) {
super.build(context);
LogUtil.log(TAG: this.runtimeType, message: "_MonthViewState build");
itemHeight = MediaQuery.of(context).size.width / 7;
totalHeight = itemHeight * lineCount + mainSpacing * (lineCount - 1);
@ -92,52 +117,57 @@ class _MonthViewState extends State<MonthView> {
}
}
return MultiSelectItemContainer(
return ItemContainer(
dateModel: dateModel,
configuration: configuration,
calendarProvider: calendarProvider,
// configuration: configuration,
// calendarProvider: calendarProvider,
);
});
}
@override
bool get wantKeepAlive => true;
}
/**
* itemitem
*/
class MultiSelectItemContainer extends StatefulWidget {
class ItemContainer extends StatefulWidget {
final DateModel dateModel;
CalendarConfiguration configuration;
CalendarProvider calendarProvider;
MultiSelectItemContainer(
{Key key, this.dateModel, this.configuration, this.calendarProvider})
: super(key: key);
// CalendarConfiguration configuration;
// CalendarProvider calendarProvider;
const ItemContainer({
Key key,
this.dateModel,
}) : super(key: key);
@override
MultiSelectItemContainerState createState() =>
MultiSelectItemContainerState();
ItemContainerState createState() => ItemContainerState();
}
class MultiSelectItemContainerState extends State<MultiSelectItemContainer> {
class ItemContainerState extends State<ItemContainer> {
DateModel dateModel;
CalendarConfiguration configuration;
CalendarProvider calendarProvider;
ValueNotifier<bool> isSelected;
@override
void initState() {
super.initState();
dateModel = widget.dateModel;
configuration = widget.configuration;
calendarProvider = widget.calendarProvider;
isSelected = ValueNotifier(dateModel.isSelected);
}
@override
Widget build(BuildContext context) {
// LogUtil.log(
// TAG: this.runtimeType,
// message: "_ItemContainerState build ${dateModel}");
return Container(
child: GestureDetector(
// LogUtil.log(TAG: this.runtimeType,message: "ItemContainerState build");
calendarProvider = Provider.of<CalendarProvider>(context, listen: false);
configuration = calendarProvider.calendarConfiguration;
return GestureDetector(
//item
behavior: HitTestBehavior.opaque,
onTap: () {
@ -177,6 +207,7 @@ class MultiSelectItemContainerState extends State<MultiSelectItemContainer> {
calendarProvider.selectDateModel = dateModel;
configuration.calendarSelect(dateModel);
//item
calendarProvider.lastClickItemState?.refreshItem();
calendarProvider.lastClickItemState = this;
}
@ -184,7 +215,11 @@ class MultiSelectItemContainerState extends State<MultiSelectItemContainer> {
refreshItem();
},
child: configuration.dayWidgetBuilder(dateModel),
),
// child: ValueListenableBuilder(
// valueListenable: isSelected,
// builder: (BuildContext context, bool value, Widget child) {
// return configuration.dayWidgetBuilder(dateModel);
// }),
);
}
@ -201,6 +236,7 @@ class MultiSelectItemContainerState extends State<MultiSelectItemContainer> {
if (mounted) {
setState(() {
dateModel.isSelected = !dateModel.isSelected;
// isSelected.value = !isSelected.value;
});
}
}

@ -2,12 +2,13 @@ import 'package:flutter/material.dart';
import 'package:flutter_custom_calendar/calendar_provider.dart';
import 'package:flutter_custom_calendar/configuration.dart';
import 'package:flutter_custom_calendar/model/date_model.dart';
import 'package:flutter_custom_calendar/utils/LogUtil.dart';
import 'package:flutter_custom_calendar/utils/date_util.dart';
import 'package:flutter_custom_calendar/widget/month_view.dart';
import 'package:provider/provider.dart';
class MonthViewPager extends StatefulWidget {
MonthViewPager();
const MonthViewPager({Key key}) : super(key: key);
@override
_MonthViewPagerState createState() => _MonthViewPagerState();
@ -18,37 +19,44 @@ class _MonthViewPagerState extends State<MonthViewPager> {
var totalHeight;
// PageController newPageController;
@override
void initState() {
LogUtil.log(TAG: this.runtimeType, message: "MonthViewPager initState");
calendarProvider = Provider.of<CalendarProvider>(context, listen: false);
//index
DateModel dateModel = calendarProvider.lastClickDateModel;
List<DateModel> monthList =
calendarProvider.calendarConfiguration.monthList;
int index = 0;
for (int i = 0; i < monthList.length; i++) {
DateModel firstDayOfMonth = monthList[i];
DateModel lastDayOfMonth = DateModel.fromDateTime(firstDayOfMonth
.getDateTime()
.add(Duration(
days: DateUtil.getMonthDaysCount(
firstDayOfMonth.year, firstDayOfMonth.month))));
// //index
// DateModel dateModel = calendarProvider.lastClickDateModel;
// List<DateModel> monthList =
// calendarProvider.calendarConfiguration.monthList;
// int index = 0;
// for (int i = 0; i < monthList.length; i++) {
// DateModel firstDayOfMonth = monthList[i];
// DateModel lastDayOfMonth = DateModel.fromDateTime(firstDayOfMonth
// .getDateTime()
// .add(Duration(
// days: DateUtil.getMonthDaysCount(
// firstDayOfMonth.year, firstDayOfMonth.month))));
//
// if ((dateModel.isAfter(firstDayOfMonth) ||
// dateModel.isSameWith(firstDayOfMonth)) &&
// dateModel.isBefore(lastDayOfMonth)) {
// index = i;
// break;
// }
// }
// WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
// calendarProvider.calendarConfiguration.monthController.jumpToPage(index);
// });
if ((dateModel.isAfter(firstDayOfMonth) ||
dateModel.isSameWith(firstDayOfMonth)) &&
dateModel.isBefore(lastDayOfMonth)) {
index = i;
break;
}
}
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
calendarProvider.calendarConfiguration.pageController.jumpToPage(index);
});
}
@override
void dispose() {
LogUtil.log(TAG: this.runtimeType, message: "MonthViewPager dispose");
super.dispose();
}
@ -64,8 +72,12 @@ class _MonthViewPagerState extends State<MonthViewPager> {
//
DateModel dateModel = configuration.monthList[position];
configuration.monthChange(dateModel.year, dateModel.month);
//
calendarProvider.lastClickDateModel = configuration.monthList[position];
//
DateModel temp = new DateModel();
temp.year = configuration.monthList[position].year;
temp.month = configuration.monthList[position].month;
temp.day = configuration.monthList[position].day + 14;
calendarProvider.lastClickDateModel = temp;
//使PageView
// double itemHeight = MediaQuery.of(context).size.width / 7;
@ -81,21 +93,13 @@ class _MonthViewPagerState extends State<MonthViewPager> {
// });
// }
},
controller: configuration.pageController,
controller: configuration.monthController,
itemBuilder: (context, index) {
DateModel dateModel = configuration.monthList[index];
final DateModel dateModel = configuration.monthList[index];
return new MonthView(
configuration: configuration,
year: dateModel.year,
month: dateModel.month,
minSelectDate: DateModel.fromDateTime(DateTime(
configuration.minSelectYear,
configuration.minSelectMonth,
configuration.minSelectDay)),
maxSelectDate: DateModel.fromDateTime(DateTime(
configuration.maxSelectYear,
configuration.maxSelectMonth,
configuration.maxSelectDay)),
extraDataMap: configuration.extraDataMap,
);
},
itemCount: configuration.monthList.length,

@ -5,6 +5,7 @@ import 'package:flutter_custom_calendar/constants/constants.dart';
import 'package:flutter_custom_calendar/controller.dart';
import 'package:flutter_custom_calendar/model/date_model.dart';
import 'package:flutter_custom_calendar/utils/date_util.dart';
import 'package:flutter_custom_calendar/widget/month_view.dart';
import 'package:provider/provider.dart';
/**
@ -14,19 +15,13 @@ class WeekView extends StatefulWidget {
final int year;
final int month;
final DateModel firstDayOfWeek;
final DateModel minSelectDate;
final DateModel maxSelectDate;
final Map<DateModel, Object> extraDataMap; //
final CalendarConfiguration configuration;
const WeekView(
{@required this.year,
@required this.month,
this.firstDayOfWeek,
this.minSelectDate,
this.maxSelectDate,
this.extraDataMap});
this.configuration});
@override
_WeekViewState createState() => _WeekViewState();
@ -35,20 +30,36 @@ class WeekView extends StatefulWidget {
class _WeekViewState extends State<WeekView> {
List<DateModel> items;
DateModel minSelectDate;
DateModel maxSelectDate;
Map<DateModel, Object> extraDataMap; //
@override
void initState() {
super.initState();
minSelectDate = DateModel.fromDateTime(DateTime(
widget.configuration.minSelectYear,
widget.configuration.minSelectMonth,
widget.configuration.minSelectDay));
maxSelectDate = DateModel.fromDateTime(DateTime(
widget.configuration.maxSelectYear,
widget.configuration.maxSelectMonth,
widget.configuration.maxSelectDay));
extraDataMap = widget.configuration.extraDataMap;
items = DateUtil.initCalendarForWeekView(
widget.year, widget.month, widget.firstDayOfWeek.getDateTime(), 0,
minSelectDate: widget.minSelectDate,
maxSelectDate: widget.maxSelectDate,
extraDataMap: widget.extraDataMap);
minSelectDate: minSelectDate,
maxSelectDate: maxSelectDate,
extraDataMap: extraDataMap);
}
@override
Widget build(BuildContext context) {
return Consumer<CalendarProvider>(
builder: (context, calendarProvider, child) {
CalendarProvider calendarProvider =
Provider.of<CalendarProvider>(context, listen: false);
CalendarConfiguration configuration =
calendarProvider.calendarConfiguration;
print(
@ -75,47 +86,11 @@ class _WeekViewState extends State<WeekView> {
}
}
return GestureDetector(
onTap: () {
//
print("GestureDetector onTap$dateModel");
print("!dateModel.isInRange:${!dateModel.isInRange}");
if (!dateModel.isInRange) {
//
if (configuration.selectMode == Constants.MODE_MULTI_SELECT) {
configuration.multiSelectOutOfRange();
}
return;
}
calendarProvider.lastClickDateModel = dateModel;
if (configuration.selectMode == Constants.MODE_MULTI_SELECT) {
//
if (calendarProvider.selectedDateList.length ==
configuration.maxMultiSelectCount) {
configuration.multiSelectOutOfSize();
return;
}
//
calendarProvider.selectDateModel = dateModel;
configuration.calendarSelect(dateModel);
// setState(() {
if (calendarProvider.selectedDateList.contains(dateModel)) {
calendarProvider.selectedDateList.remove(dateModel);
} else {
calendarProvider.selectedDateList.add(dateModel);
}
// });
} else {
calendarProvider.selectDateModel = dateModel;
configuration.calendarSelect(dateModel);
// setState(() {});
}
},
child: configuration.dayWidgetBuilder(dateModel),
return ItemContainer(
dateModel: dateModel,
// configuration: configuration,
// calendarProvider: calendarProvider,
);
});
});
}
}

@ -3,11 +3,12 @@ import 'package:flutter_custom_calendar/calendar_provider.dart';
import 'package:flutter_custom_calendar/configuration.dart';
import 'package:flutter_custom_calendar/controller.dart';
import 'package:flutter_custom_calendar/model/date_model.dart';
import 'package:flutter_custom_calendar/utils/LogUtil.dart';
import 'package:flutter_custom_calendar/widget/week_view.dart';
import 'package:provider/provider.dart';
class WeekViewPager extends StatefulWidget {
WeekViewPager();
const WeekViewPager({Key key}) : super(key: key);
@override
_WeekViewPagerState createState() => _WeekViewPagerState();
@ -17,45 +18,27 @@ class _WeekViewPagerState extends State<WeekViewPager> {
int lastMonth; //
CalendarProvider calendarProvider;
// PageController newPageController;
@override
void initState() {
print("WeekViewPager initState");
LogUtil.log(TAG: this.runtimeType, message: "WeekViewPager initState");
calendarProvider = Provider.of<CalendarProvider>(context, listen: false);
lastMonth = calendarProvider.lastClickDateModel.month;
//index
DateModel dateModel = calendarProvider.lastClickDateModel;
List<DateModel> weekList = calendarProvider.calendarConfiguration.weekList;
int index = 0;
for (int i = 0; i < weekList.length; i++) {
DateModel firstDayOfWeek = weekList[i];
DateModel lastDayOfWeek = DateModel.fromDateTime(
firstDayOfWeek.getDateTime().add(Duration(days: 7)));
if ((dateModel.isSameWith(weekList[i]) ||
dateModel.isAfter(weekList[i])) &&
dateModel.isBefore(lastDayOfWeek)) {
index = i;
break;
}
}
// print("weekList:$weekList");
// print("当前周:index:$index");
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
calendarProvider.calendarConfiguration.weekController.jumpToPage(index);
});
}
@override
void dispose() {
print("WeekViewPager dispose");
LogUtil.log(TAG: this.runtimeType, message: "WeekViewPager dispose");
super.dispose();
}
@override
Widget build(BuildContext context) {
LogUtil.log(TAG: this.runtimeType, message: "WeekViewPager build");
// CalendarProvider,listenfalse
CalendarProvider calendarProvider =
Provider.of<CalendarProvider>(context, listen: false);
@ -63,6 +46,7 @@ class _WeekViewPagerState extends State<WeekViewPager> {
calendarProvider.calendarConfiguration;
return Container(
height: configuration.itemSize ?? MediaQuery.of(context).size.width / 7,
child: PageView.builder(
onPageChanged: (position) {
//
@ -71,28 +55,19 @@ class _WeekViewPagerState extends State<WeekViewPager> {
if (lastMonth != currentMonth) {
configuration.monthChange(
firstDayOfWeek.year, firstDayOfWeek.month);
lastMonth = currentMonth;
}
calendarProvider.lastClickDateModel =
configuration.weekList[position];
// DateModel dateModel = configuration.weekList[position];
// configuration.monthChange(dateModel.year, dateModel.month);
// calendarProvider.lastClickDateModel = configuration.weekList[position]
// ..day += 4;
},
controller: configuration.weekController,
controller: calendarProvider.calendarConfiguration.weekController,
itemBuilder: (context, index) {
DateModel dateModel = configuration.weekList[index];
return new WeekView(
year: dateModel.year,
month: dateModel.month,
firstDayOfWeek: dateModel,
minSelectDate: DateModel.fromDateTime(DateTime(
configuration.minSelectYear,
configuration.minSelectMonth,
configuration.minSelectDay)),
maxSelectDate: DateModel.fromDateTime(DateTime(
configuration.maxSelectYear,
configuration.maxSelectMonth,
configuration.maxSelectDay)),
extraDataMap: configuration.extraDataMap,
configuration: calendarProvider.calendarConfiguration,
);
},
itemCount: configuration.weekList.length,

Loading…
Cancel
Save