From 6dcf7c21a2e1f200d47b0923283de123fd97fcde Mon Sep 17 00:00:00 2001 From: xiaodong <450468291@qq.com> Date: Wed, 9 Oct 2019 10:01:43 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=9B=E5=BB=BAconfiguration=E7=B1=BB?= =?UTF-8?q?=EF=BC=8C=E5=B0=86=E9=85=8D=E7=BD=AE=E7=9A=84=E4=BF=A1=E6=81=AF?= =?UTF-8?q?=E6=94=BE=E5=88=B0=E8=BF=99=E9=87=8C=20=E5=BC=95=E5=85=A5provid?= =?UTF-8?q?er=E7=8A=B6=E6=80=81=E7=AE=A1=E7=90=86,=E9=81=BF=E5=85=8D?= =?UTF-8?q?=E6=B7=B1=E5=B1=82=E5=B5=8C=E5=A5=97=E4=BC=A0=E9=80=92=E4=BF=A1?= =?UTF-8?q?=E6=81=AF=20=E5=91=A8=E8=A7=86=E5=9B=BE=E5=92=8C=E6=9C=88?= =?UTF-8?q?=E8=A7=86=E5=9B=BE=EF=BC=8C=E8=81=94=E5=8A=A8=20=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E6=97=A5=E5=BF=97=E8=BE=93=E5=87=BA=E7=B1=BBLogUtil?= =?UTF-8?q?=EF=BC=8C=E6=96=B9=E4=BE=BF=E6=9F=A5=E7=9C=8B=E8=B0=83=E8=AF=95?= =?UTF-8?q?=20=E5=A2=9E=E5=8A=A0example=E4=BE=8B=E5=AD=90=20=E6=80=A7?= =?UTF-8?q?=E8=83=BD=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 46 +++--- example/lib/default_style_page.dart | 6 +- example/lib/main.dart | 8 +- example/pubspec.lock | 51 ++++++- lib/cache_data.dart | 26 ++++ lib/calendar_provider.dart | 68 ++++++++- lib/configuration.dart | 13 +- lib/controller.dart | 124 +++++++++++----- lib/model/date_model.dart | 7 + lib/utils/date_util.dart | 10 +- lib/widget/base_day_view.dart | 4 +- lib/widget/calendar_view.dart | 87 +++++++++-- lib/widget/default_custom_day_view.dart | 2 +- lib/widget/month_view.dart | 182 ++++++++++++++---------- lib/widget/month_view_pager.dart | 76 +++++----- lib/widget/week_view.dart | 131 +++++++---------- lib/widget/week_view_pager.dart | 53 ++----- 17 files changed, 578 insertions(+), 316 deletions(-) create mode 100644 lib/cache_data.dart diff --git a/README.md b/README.md index d0490b7..f4e9fb0 100644 --- a/README.md +++ b/README.md @@ -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个方面的配置。 * 一个是显示日历所需要的相关数据, @@ -64,9 +65,10 @@ CalendarViewWidget({@required this.calendarController, this.boxDecoration}); * 一个是对日历的监听事件进行配置。 ``` -//构造函数 - CalendarController( + //构造函数 + 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 selectedDateTimeList = EMPTY_SET, DateModel selectDateModel, int maxMultiSelectCount = 9999, - Map extraDataMap = EMPTY_MAP}) + double verticalSpacing = 10, + bool enableExpand = true, + Map extraDataMap = EMPTY_MAP}) ``` -数据方面的配置 +### 数据方面的配置 属性 | 含义 | 默认值 :-: | :-: | :-: @@ -111,7 +115,7 @@ maxMultiSelectCount | 多选,最多选多少个| hhh extraDataMap | 自定义额外的数据| 默认为空Map,Map 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 expandChange)|监听日历的展开收缩状态| -### 利用controller来控制日历的切换,支持配置动画 +## 利用controller来控制日历的切换,支持配置动画 方法 | 含义 | 默认值 :-: | :-: | :-: 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 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 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|默认为空 方法|含义| diff --git a/example/lib/default_style_page.dart b/example/lib/default_style_page.dart index 9b84822..595fd0b 100644 --- a/example/lib/default_style_page.dart +++ b/example/lib/default_style_page.dart @@ -23,8 +23,12 @@ class _DefaultStylePageState extends State { @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) { diff --git a/example/lib/main.dart b/example/lib/main.dart index 8b0ebbc..bb3056e 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -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: { "/default": (context) => DefaultStylePage( title: "默认风格+单选", diff --git a/example/pubspec.lock b/example/pubspec.lock index 86eee3b..1b7b8bb 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -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" diff --git a/lib/cache_data.dart b/lib/cache_data.dart new file mode 100644 index 0000000..eb48796 --- /dev/null +++ b/lib/cache_data.dart @@ -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> monthListCache = Map(); + Map> weekListCache = Map(); + + static CacheData getInstance() { + if (_instance == null) { + _instance = new CacheData._(); + } + return _instance; + } +} + + + diff --git a/lib/calendar_provider.dart b/lib/calendar_provider.dart index 8a9bdf0..5ee04f2 100644 --- a/lib/calendar_provider.dart +++ b/lib/calendar_provider.dart @@ -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 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(); + } + + //根据lastClickDateModel,去计算需要展示的星期视图的初始index + 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; + } + + //根据lastClickDateModel,去计算需要展示的月视图的index + 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 expandStatus = ValueNotifier(true); //当前展开状态 @@ -43,7 +95,15 @@ class CalendarProvider extends ChangeNotifier { //lastClickDateModel,默认是选中的item,如果为空的话,默认是当前的时间 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); +// } +// }); } //退出的时候,清除数据 diff --git a/lib/configuration.dart b/lib/configuration.dart index be3413a..e2ca071 100644 --- a/lib/configuration.dart +++ b/lib/configuration.dart @@ -9,8 +9,11 @@ class CalendarConfiguration { //默认是单选,可以配置为MODE_SINGLE_SELECT,MODE_MULTI_SELECT int selectMode; + //仅展示月视图,仅展示周视图,支持月视图和周视图切换 + int showMode; + bool defaultExpandStatus; //展开状态,true代表是月视图,false代表是周视图 - bool enableExpand; //是否可以展开 + bool enableExpand; //是否可以展开,true只展示月视图,false仅展示周视图, //日历显示的最小年份和最大年份 int minYear; @@ -42,6 +45,7 @@ class CalendarConfiguration { */ double verticalSpacing; //日历item之间的竖直方向间距,默认10 BoxDecoration boxDecoration; //整体的背景设置 + double itemSize; //默认是屏幕宽度/7 //支持自定义绘制 DayWidgetBuilder dayWidgetBuilder; //创建日历item @@ -61,7 +65,7 @@ class CalendarConfiguration { */ List monthList = new List(); //月份list List 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}'; } } diff --git a/lib/controller.dart b/lib/controller.dart index 0bc6046..4ae9fab 100644 --- a/lib/controller.dart +++ b/lib/controller.dart @@ -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 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 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}) { // 如果当前显示的是周视图的话,需要计算出第一个月的index后,调用weekController 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 { // 如果当前显示的是周视图的话,需要计算出第一个月的index后,调用weekController 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(); } /** diff --git a/lib/model/date_model.dart b/lib/model/date_model.dart index 61c6bb9..4061ea2 100644 --- a/lib/model/date_model.dart +++ b/lib/model/date_model.dart @@ -11,6 +11,13 @@ class DateModel { List lunar = List(3); +// List get lunar { +// if (lunar?.isNotEmpty == false) { +// return lunar; +// } +//// return LunarUtil.solarToLunar(year, month, day); +// } + //农历字符串 String get lunarString { if (solarTerm.isNotEmpty) { diff --git a/lib/utils/date_util.dart b/lib/utils/date_util.dart index 2117eb3..856feee 100644 --- a/lib/utils/date_util.dart +++ b/lib/utils/date_util.dart @@ -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 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 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 extraDataMap}) { - LogUtil.log(TAG: "DateUtil", message: "initCalendarForWeekView"); List 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]; } diff --git a/lib/widget/base_day_view.dart b/lib/widget/base_day_view.dart index a1894cb..17d0808 100644 --- a/lib/widget/base_day_view.dart +++ b/lib/widget/base_day_view.dart @@ -6,9 +6,9 @@ import 'package:flutter_custom_calendar/model/date_model.dart'; * 通过canvas自定义item,只需实现相关的方法就可以 */ abstract class BaseCustomDayWidget extends StatelessWidget { - DateModel dateModel; + final DateModel dateModel; - BaseCustomDayWidget( + const BaseCustomDayWidget( this.dateModel, ); diff --git a/lib/widget/calendar_view.dart b/lib/widget/calendar_view.dart index b2e4b96..14f1716 100644 --- a/lib/widget/calendar_view.dart +++ b/lib/widget/calendar_view.dart @@ -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 CalendarProvider calendarProvider; + var state = CrossFadeState.showFirst; + + List widgets; + + int index = 0; + @override void initState() { calendarProvider = Provider.of(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 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: [ +// /** +// * 利用const,避免每次setState都会刷新到这顶部的view +// */ +// 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: [ /** * 利用const,避免每次setState都会刷新到这顶部的view */ calendarProvider.calendarConfiguration.weekBarItemWidgetBuilder(), AnimatedContainer( - duration: Duration(milliseconds: 200), - height: expand ? totalHeight : itemHeight, - child: expand - ? Container( - height: totalHeight, - child: MonthViewPager(), - ) - : Container( - height: itemHeight, - child: WeekViewPager(), - ), - ), + duration: Duration(milliseconds: 500), + height: expand ? totalHeight : itemHeight, + child: IndexedStack( +// overflow: Overflow.visible, + index: index, + children: widgets, + )), ], ), ); diff --git a/lib/widget/default_custom_day_view.dart b/lib/widget/default_custom_day_view.dart index 3dd1f92..d972d03 100644 --- a/lib/widget/default_custom_day_view.dart +++ b/lib/widget/default_custom_day_view.dart @@ -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) { diff --git a/lib/widget/month_view.dart b/lib/widget/month_view.dart index 8209ecb..120eebb 100644 --- a/lib/widget/month_view.dart +++ b/lib/widget/month_view.dart @@ -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 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 { +class _MonthViewState extends State + with AutomaticKeepAliveClientMixin { List items; int lineCount; @@ -42,21 +42,46 @@ class _MonthViewState extends State { double totalHeight; double mainSpacing = 10; + DateModel minSelectDate; + DateModel maxSelectDate; + Map extraDataMap; //自定义额外的数据 + @override void initState() { super.initState(); - items = DateUtil.initCalendarForMonthView( - widget.year, widget.month, DateTime.now(), DateTime.sunday, - minSelectDate: widget.minSelectDate, - maxSelectDate: widget.maxSelectDate, - extraDataMap: widget.extraDataMap); + 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: 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,99 +117,109 @@ class _MonthViewState extends State { } } - return MultiSelectItemContainer( + return ItemContainer( dateModel: dateModel, - configuration: configuration, - calendarProvider: calendarProvider, +// configuration: configuration, +// calendarProvider: calendarProvider, ); }); } + + @override + bool get wantKeepAlive => true; } /** * 多选模式,包装item,这样的话,就只需要刷新当前点击的item就行了,不需要刷新整个页面 */ -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 { +class ItemContainerState extends State { DateModel dateModel; CalendarConfiguration configuration; CalendarProvider calendarProvider; + ValueNotifier 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( - //点击整个item都会触发事件 - behavior: HitTestBehavior.opaque, - onTap: () { - LogUtil.log( - TAG: this.runtimeType, - message: "GestureDetector onTap: $dateModel}"); - - //范围外不可点击 - if (!dateModel.isInRange) { - //多选回调 - if (configuration.selectMode == Constants.MODE_MULTI_SELECT) { - configuration.multiSelectOutOfRange(); - } - return; +// LogUtil.log(TAG: this.runtimeType,message: "ItemContainerState build"); + calendarProvider = Provider.of(context, listen: false); + configuration = calendarProvider.calendarConfiguration; + + return GestureDetector( + //点击整个item都会触发事件 + behavior: HitTestBehavior.opaque, + onTap: () { + LogUtil.log( + TAG: this.runtimeType, + message: "GestureDetector onTap: $dateModel}"); + + //范围外不可点击 + 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.lastClickDateModel = dateModel; - configuration.calendarSelect(dateModel); - if (calendarProvider.selectedDateList.contains(dateModel)) { - calendarProvider.selectedDateList.remove(dateModel); - } else { - calendarProvider.selectedDateList.add(dateModel); - } + if (configuration.selectMode == Constants.MODE_MULTI_SELECT) { + //多选,判断是否超过限制,超过范围 + if (calendarProvider.selectedDateList.length == + configuration.maxMultiSelectCount) { + configuration.multiSelectOutOfSize(); + return; + } - //多选也可以弄这些单选的代码 - calendarProvider.selectDateModel = dateModel; + configuration.calendarSelect(dateModel); + if (calendarProvider.selectedDateList.contains(dateModel)) { + calendarProvider.selectedDateList.remove(dateModel); } else { - calendarProvider.selectDateModel = dateModel; - configuration.calendarSelect(dateModel); - - calendarProvider.lastClickItemState?.refreshItem(); - calendarProvider.lastClickItemState = this; + calendarProvider.selectedDateList.add(dateModel); } - refreshItem(); - }, - child: configuration.dayWidgetBuilder(dateModel), - ), + //多选也可以弄这些单选的代码 + calendarProvider.selectDateModel = dateModel; + } else { + calendarProvider.selectDateModel = dateModel; + configuration.calendarSelect(dateModel); + + //单选需要刷新上一个item + calendarProvider.lastClickItemState?.refreshItem(); + calendarProvider.lastClickItemState = this; + } + + refreshItem(); + }, + child: configuration.dayWidgetBuilder(dateModel), +// child: ValueListenableBuilder( +// valueListenable: isSelected, +// builder: (BuildContext context, bool value, Widget child) { +// return configuration.dayWidgetBuilder(dateModel); +// }), ); } @@ -198,9 +233,10 @@ class MultiSelectItemContainerState extends State { The following assertion was thrown while handling a gesture: setState() called after dispose() */ - if(mounted){ + if (mounted) { setState(() { dateModel.isSelected = !dateModel.isSelected; +// isSelected.value = !isSelected.value; }); } } diff --git a/lib/widget/month_view_pager.dart b/lib/widget/month_view_pager.dart index 854b47a..e6546e2 100644 --- a/lib/widget/month_view_pager.dart +++ b/lib/widget/month_view_pager.dart @@ -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 { var totalHeight; +// PageController newPageController; + @override void initState() { + LogUtil.log(TAG: this.runtimeType, message: "MonthViewPager initState"); + calendarProvider = Provider.of(context, listen: false); - //计算当前月视图的index - DateModel dateModel = calendarProvider.lastClickDateModel; - List 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 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 { //月份的变化 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 { // }); // } }, - 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, diff --git a/lib/widget/week_view.dart b/lib/widget/week_view.dart index 59818ae..c71bb6f 100644 --- a/lib/widget/week_view.dart +++ b/lib/widget/week_view.dart @@ -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 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,87 +30,67 @@ class WeekView extends StatefulWidget { class _WeekViewState extends State { List items; + DateModel minSelectDate; + DateModel maxSelectDate; + + Map 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( - builder: (context, calendarProvider, child) { - CalendarConfiguration configuration = - calendarProvider.calendarConfiguration; - print( - "WeekView Consumer:calendarProvider.selectDateModel:${calendarProvider.selectDateModel}"); - return new GridView.builder( - physics: NeverScrollableScrollPhysics(), - gridDelegate: new SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 7, mainAxisSpacing: 10), - itemCount: 7, - itemBuilder: (context, index) { - DateModel dateModel = items[index]; - //判断是否被选择 - if (configuration.selectMode == Constants.MODE_MULTI_SELECT) { - if (calendarProvider.selectedDateList.contains(dateModel)) { - dateModel.isSelected = true; - } else { - dateModel.isSelected = false; - } + CalendarProvider calendarProvider = + Provider.of(context, listen: false); + + CalendarConfiguration configuration = + calendarProvider.calendarConfiguration; + print( + "WeekView Consumer:calendarProvider.selectDateModel:${calendarProvider.selectDateModel}"); + return new GridView.builder( + physics: NeverScrollableScrollPhysics(), + gridDelegate: new SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 7, mainAxisSpacing: 10), + itemCount: 7, + itemBuilder: (context, index) { + DateModel dateModel = items[index]; + //判断是否被选择 + if (configuration.selectMode == Constants.MODE_MULTI_SELECT) { + if (calendarProvider.selectedDateList.contains(dateModel)) { + dateModel.isSelected = true; } else { - if (calendarProvider.selectDateModel == dateModel) { - dateModel.isSelected = true; - } else { - dateModel.isSelected = false; - } + dateModel.isSelected = false; } + } else { + if (calendarProvider.selectDateModel == dateModel) { + dateModel.isSelected = true; + } else { + dateModel.isSelected = false; + } + } - 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, + ); + }); } } diff --git a/lib/widget/week_view_pager.dart b/lib/widget/week_view_pager.dart index b1885fb..965f77e 100644 --- a/lib/widget/week_view_pager.dart +++ b/lib/widget/week_view_pager.dart @@ -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 { int lastMonth; //保存上一个月份,不然不知道月份发生了变化 CalendarProvider calendarProvider; +// PageController newPageController; + @override void initState() { - print("WeekViewPager initState"); + LogUtil.log(TAG: this.runtimeType, message: "WeekViewPager initState"); calendarProvider = Provider.of(context, listen: false); lastMonth = calendarProvider.lastClickDateModel.month; - //计算当前周视图的index - DateModel dateModel = calendarProvider.lastClickDateModel; - List 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对象,设置listen为false,不需要刷新 CalendarProvider calendarProvider = Provider.of(context, listen: false); @@ -63,6 +46,7 @@ class _WeekViewPagerState extends State { 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 { 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,