diff --git a/example/lib/default_style_page.dart b/example/lib/default_style_page.dart index 26faeb5..9ac4a99 100644 --- a/example/lib/default_style_page.dart +++ b/example/lib/default_style_page.dart @@ -1,3 +1,4 @@ +import 'package:example/main.dart'; import 'package:flutter/material.dart'; import 'package:flutter_custom_calendar/flutter_custom_calendar.dart'; @@ -19,7 +20,8 @@ class _DefaultStylePageState extends State { void initState() { text = "${DateTime.now().year}年${DateTime.now().month}月"; - controller = new CalendarController(); + controller = new CalendarController( + minYear: 2019, minYearMonth: 8, maxYear: 2019, maxYearMonth: 9); controller.addMonthChangeListener( (year, month) { @@ -50,13 +52,15 @@ class _DefaultStylePageState extends State { new IconButton( icon: Icon(Icons.navigate_before), onPressed: () { - controller.moveToPreviousMonth(); +// controller.moveToPreviousMonth(); + controller.previousPage(); }), new Text(text), new IconButton( icon: Icon(Icons.navigate_next), onPressed: () { - controller.moveToNextMonth(); +// controller.moveToNextMonth(); + controller.nextPage(); }), ], ), @@ -69,7 +73,9 @@ class _DefaultStylePageState extends State { ), ), floatingActionButton: FloatingActionButton( - onPressed: () {}, + onPressed: () { + controller.toggleExpandStatus(); + }, tooltip: 'Increment', child: Icon(Icons.add), ), // This trailing comma makes auto-formatting nicer for build methods. diff --git a/lib/CalendarProvider.dart b/lib/calendar_provider.dart similarity index 76% rename from lib/CalendarProvider.dart rename to lib/calendar_provider.dart index 30db4be..1455214 100644 --- a/lib/CalendarProvider.dart +++ b/lib/calendar_provider.dart @@ -10,6 +10,7 @@ import 'package:flutter_custom_calendar/model/date_model.dart'; class CalendarProvider extends ChangeNotifier { Set selectedDateList = new Set(); //被选中的日期,用于多选 DateModel _selectDateModel; //当前选中的日期,用于单选 + DateModel lastClickDateModel; //保存最后点击的一个日期,用于周视图与月视图之间的切换和同步 DateModel get selectDateModel => _selectDateModel; @@ -19,6 +20,8 @@ class CalendarProvider extends ChangeNotifier { notifyListeners(); } + ValueNotifier expandStatus = ValueNotifier(true); //当前展开状态 + //配置类也放这里吧,这样的话,所有子树,都可以拿到配置的信息 CalendarConfiguration calendarConfiguration; @@ -32,6 +35,10 @@ class CalendarProvider extends ChangeNotifier { } this.selectDateModel = selectDateModel; this.calendarConfiguration = calendarConfiguration; + //lastClickDateModel,默认是选中的item,如果为空的话,默认是当前的时间 + this.lastClickDateModel = selectDateModel != null + ? selectDateModel + : DateModel.fromDateTime(DateTime.now()); } //退出的时候,清除数据 diff --git a/lib/configuration.dart b/lib/configuration.dart index 2a191a0..2b148d5 100644 --- a/lib/configuration.dart +++ b/lib/configuration.dart @@ -10,7 +10,7 @@ class CalendarConfiguration { int selectMode; //展开状态 - bool expandStatus; + bool defaultExpandStatus; //日历显示的最小年份和最大年份 int minYear; @@ -60,7 +60,6 @@ class CalendarConfiguration { CalendarConfiguration( {this.selectMode, - this.expandStatus, this.minYear, this.maxYear, this.minYearMonth, @@ -79,10 +78,13 @@ class CalendarConfiguration { this.monthList, this.weekList, this.pageController, - this.weekController}); + this.weekController, + bool defaultExpandStatus = true}) { + this.defaultExpandStatus = defaultExpandStatus; + } @override String toString() { - return 'CalendarConfiguration{selectMode: $selectMode, expandStatus: $expandStatus, 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, pageController: $pageController, weekController: $weekController}'; } } diff --git a/lib/controller.dart b/lib/controller.dart index cd42d14..280d4b2 100644 --- a/lib/controller.dart +++ b/lib/controller.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:flutter_custom_calendar/CalendarProvider.dart'; +import 'package:flutter_custom_calendar/calendar_provider.dart'; import 'package:flutter_custom_calendar/configuration.dart'; import 'package:flutter_custom_calendar/utils/date_util.dart'; import 'package:flutter_custom_calendar/widget/default_combine_day_view.dart'; @@ -16,6 +16,7 @@ import 'package:provider/provider.dart'; class CalendarController { static const Set EMPTY_SET = {}; static const Map EMPTY_MAP = {}; + static const Duration DEFAULT_DURATION = const Duration(milliseconds: 500); CalendarConfiguration calendarConfiguration; @@ -26,11 +27,9 @@ class CalendarController { */ List monthList = new List(); //月份list List weekList = new List(); //星期list - PageController pageController; //月份的controller + PageController monthController; //月份的controller PageController weekController; //星期的controller - ValueNotifier expandChanged; //扩展模式发生变化 - CalendarController( {int selectMode = Constants.MODE_SINGLE_SELECT, bool expandStatus = true, @@ -52,7 +51,7 @@ class CalendarController { DateModel selectDateModel, int maxMultiSelectCount = 9999, Map extraDataMap = EMPTY_MAP}) { - this.expandChanged = ValueNotifier(expandStatus); +// this.expandChanged = ValueNotifier(expandStatus); calendarConfiguration = CalendarConfiguration( selectMode: selectMode, @@ -67,6 +66,7 @@ class CalendarController { minSelectDay: minSelectDay, maxSelectYear: maxSelectYear, maxSelectMonth: maxSelectMonth, + defaultExpandStatus: expandStatus, maxSelectDay: maxSelectDay); calendarConfiguration.dayWidgetBuilder = dayWidgetBuilder; @@ -107,7 +107,7 @@ class CalendarController { nowMonthIndex++; } } - this.pageController = new PageController(initialPage: initialPage); + this.monthController = new PageController(initialPage: initialPage); //计算一共多少周 //计算方法:第一天是周几,最后一天是周几,中间的天数/7后加上2就是结果了 @@ -125,16 +125,17 @@ class CalendarController { DateUtil.getMonthDaysCount(maxYear, maxYearMonth)); print("最后一天:$lastDay"); for (DateTime dateTime = firstWeekDate; - dateTime.isBefore(lastDay); + !dateTime.isAfter(lastDay); dateTime = dateTime.add(Duration(days: 7))) { DateModel dateModel = DateModel.fromDateTime(dateTime); weekList.add(dateModel); } this.weekController = new PageController(); + print("weekList:$weekList"); calendarConfiguration.monthList = monthList; calendarConfiguration.weekList = weekList; - calendarConfiguration.pageController = pageController; + calendarConfiguration.pageController = monthController; calendarConfiguration.weekController = weekController; calendarConfiguration.dayWidgetBuilder = dayWidgetBuilder; calendarConfiguration.weekBarItemWidgetBuilder = weekBarItemWidgetBuilder; @@ -160,6 +161,74 @@ class CalendarController { this.calendarConfiguration.multiSelectOutOfSize = listener; } + //切换展开状态 + void toggleExpandStatus() { + calendarProvider.expandStatus.value = !calendarProvider.expandStatus.value; + print("toggleExpandStatus:${calendarProvider.expandStatus.value}"); + } + + //监听展开变化 + void addExpandChangeListener(ValueChanged expandChange) { + calendarProvider.expandStatus.addListener(() { + expandChange(calendarProvider.expandStatus.value); + }); + } + + /** + * 月份或者星期的上一页 + */ + Future previousPage() async { + if (calendarProvider.expandStatus.value == true) { + //月视图 + int currentIndex = monthController.page.toInt(); + if (currentIndex == 0) { + return false; + } else { + monthController.previousPage( + duration: DEFAULT_DURATION, curve: Curves.ease); + return true; + } + } else { + //周视图 + int currentIndex = weekController.page.toInt(); + if (currentIndex == 0) { + return false; + } else { + weekController.previousPage( + duration: DEFAULT_DURATION, curve: Curves.ease); + return true; + } + } + } + + /** + * 月份或者星期的下一页 + * true:成功 + * false:是最后一页 + */ + Future nextPage() async { + if (calendarProvider.expandStatus.value == true) { + //月视图 + int currentIndex = monthController.page.toInt(); + if (monthList.length - 1 == currentIndex) { + return false; + } else { + monthController.nextPage( + duration: DEFAULT_DURATION, curve: Curves.ease); + return true; + } + } else { + //周视图 + int currentIndex = weekController.page.toInt(); + if (weekList.length - 1 == currentIndex) { + return false; + } else { + weekController.nextPage(duration: DEFAULT_DURATION, curve: Curves.ease); + return true; + } + } + } + //跳转到指定日期 void moveToCalendar(int year, int month, int day, {bool needAnimation = false, @@ -171,11 +240,14 @@ class CalendarController { if (targetPage == -1) { return; } + if (monthController.hasClients == false) { + return; + } if (needAnimation) { - pageController.animateToPage(targetPage, + monthController.animateToPage(targetPage, duration: duration, curve: curve); } else { - pageController.jumpToPage(targetPage); + monthController.jumpToPage(targetPage); } } @@ -185,7 +257,7 @@ class CalendarController { Duration duration = const Duration(milliseconds: 500), Curve curve = Curves.ease}) { DateTime targetDateTime = - monthList[pageController.page.toInt() + 12].getDateTime(); + monthList[monthController.page.toInt() + 12].getDateTime(); moveToCalendar( targetDateTime.year, targetDateTime.month, targetDateTime.day, needAnimation: needAnimation, duration: duration, curve: curve); @@ -197,7 +269,7 @@ class CalendarController { Duration duration = const Duration(milliseconds: 500), Curve curve = Curves.ease}) { DateTime targetDateTime = - monthList[pageController.page.toInt() - 12].getDateTime(); + monthList[monthController.page.toInt() - 12].getDateTime(); moveToCalendar( targetDateTime.year, targetDateTime.month, targetDateTime.day, needAnimation: needAnimation, duration: duration, curve: curve); @@ -208,8 +280,24 @@ class CalendarController { {bool needAnimation = false, Duration duration = const Duration(milliseconds: 500), 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++) { + if (weekList[i].month != currentMonth) { + weekController.jumpToPage(i); + break; + } + } + return; + } + + if ((monthController.page.toInt() + 1) >= monthList.length) { + print("moveToNextMonth:当前是最后一个月份"); + return; + } DateTime targetDateTime = - monthList[pageController.page.toInt() + 1].getDateTime(); + monthList[monthController.page.toInt() + 1].getDateTime(); moveToCalendar( targetDateTime.year, targetDateTime.month, targetDateTime.day, needAnimation: needAnimation, duration: duration, curve: curve); @@ -220,8 +308,27 @@ class CalendarController { {bool needAnimation = false, Duration duration = const Duration(milliseconds: 500), 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 >= 0; i--) { + if (weekList[i].month != currentMonth && + weekList[i].isAfter(DateModel.fromDateTime(DateTime( + calendarConfiguration.minYear, + calendarConfiguration.minYearMonth)))) { + weekController.jumpToPage(i); + break; + } + } + return; + } + + if ((monthController.page.toInt()) == 0) { + print("moveToPreviousMonth:当前是第一个月份"); + return; + } DateTime targetDateTime = - monthList[pageController.page.toInt() - 1].getDateTime(); + monthList[monthController.page.toInt() - 1].getDateTime(); moveToCalendar( targetDateTime.year, targetDateTime.month, targetDateTime.day, needAnimation: needAnimation, duration: duration, curve: curve); @@ -229,7 +336,7 @@ class CalendarController { // 获取当前的月份 DateModel getCurrentMonth() { - return monthList[pageController.page.toInt()]; + return monthList[monthController.page.toInt()]; } //获取被选中的日期,多选 @@ -241,14 +348,6 @@ class CalendarController { DateModel getSingleSelectCalendar() { return calendarProvider.selectDateModel; } - - //切换展开状态 - void toggleExpandStatus() { - expandChanged.value = !expandChanged.value; - print("toggleExpandStatus:${expandChanged.value}"); - } - - void addExpandChangeListener() {} } /** diff --git a/lib/model/date_model.dart b/lib/model/date_model.dart index 2276490..9ed80ef 100644 --- a/lib/model/date_model.dart +++ b/lib/model/date_model.dart @@ -68,7 +68,13 @@ class DateModel { day == dateModel.day; } + //是否在某天之后 + bool isAfter(DateModel dateModel) { + return this.getDateTime().isAfter(dateModel.getDateTime()); + } - - + //是否在某天之前 + bool isBefore(DateModel dateModel) { + return this.getDateTime().isBefore(dateModel.getDateTime()); + } } diff --git a/lib/utils/date_util.dart b/lib/utils/date_util.dart index 0e4b65f..f6bae9f 100644 --- a/lib/utils/date_util.dart +++ b/lib/utils/date_util.dart @@ -191,6 +191,7 @@ class DateUtil { {DateModel minSelectDate, DateModel maxSelectDate, Map extraDataMap}) { + print("initCalendarForWeekView"); List items = List(); int weekDay = currentDate.weekday; @@ -201,11 +202,24 @@ class DateUtil { for (int i = 1; i <= 7; i++) { DateModel dateModel = DateModel.fromDateTime(firstDayOfWeek.add(Duration(days: i))); - items.add(dateModel); - } - print("items.toString():${items.toString()}"); + //判断是否在范围内 + if (dateModel.getDateTime().isAfter(minSelectDate.getDateTime()) && + dateModel.getDateTime().isBefore(maxSelectDate.getDateTime())) { + dateModel.isInRange = true; + } else { + dateModel.isInRange = false; + } + //将自定义额外的数据,存储到相应的model中 + if (extraDataMap != null && extraDataMap.isNotEmpty) { + DateTime dateTime = dateModel.getDateTime(); + if (extraDataMap.containsKey(dateTime)) { + dateModel.extraData = extraDataMap[dateTime]; + } + } + items.add(dateModel); + } return items; } } diff --git a/lib/widget/calendar_view.dart b/lib/widget/calendar_view.dart index dde513b..cdf3647 100644 --- a/lib/widget/calendar_view.dart +++ b/lib/widget/calendar_view.dart @@ -1,8 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_custom_calendar/CalendarProvider.dart'; -import 'package:flutter_custom_calendar/configuration.dart'; -import 'package:flutter_custom_calendar/constants/constants.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/widget/month_view_pager.dart'; @@ -19,7 +16,7 @@ class CalendarViewWidget extends StatefulWidget { BoxDecoration boxDecoration; //控制器 - CalendarController calendarController; + final CalendarController calendarController; CalendarViewWidget( {Key key, @required this.calendarController, this.boxDecoration}) @@ -32,8 +29,10 @@ class CalendarViewWidget extends StatefulWidget { class _CalendarViewWidgetState extends State { @override void initState() { + //初始化一些数据,一些跟状态有关的要放到provider中 widget.calendarController.calendarProvider.initData( calendarConfiguration: widget.calendarController.calendarConfiguration); + super.initState(); } @@ -44,6 +43,7 @@ class _CalendarViewWidgetState extends State { child: Container( //外部可以自定义背景设置 decoration: widget.boxDecoration, + //使用const,保证外界的setState不会刷新日历这个widget child: const CalendarContainer()), ); } @@ -63,15 +63,17 @@ class CalendarContainerState extends State bool expand = true; + CalendarProvider calendarProvider; + @override void initState() { -// widget.calendarController.expandChanged.addListener(() { -// print("_CalendarViewWidgetState:$expand"); -// setState(() { -// expand = !expand; -// }); -// }); -// + calendarProvider = Provider.of(context, listen: false); + expand = calendarProvider.expandStatus.value; + calendarProvider.expandStatus.addListener(() { + setState(() { + expand = !expand; + }); + }); } @override @@ -91,85 +93,20 @@ class CalendarContainerState extends State /** * 利用const,避免每次setState都会刷新到这顶部的view */ -// widget.calendarController.weekBarItemWidgetBuilder(), + calendarProvider.calendarConfiguration.weekBarItemWidgetBuilder(), AnimatedContainer( - duration: Duration(milliseconds: 500), - height: expand ? totalHeight : itemHeight, - child: -// expand ? - Container( - height: totalHeight, - child: MonthViewPager( -// selectMode: widget.calendarController.selectMode, -// monthChange: (int year, int month) { -// widget.calendarController.monthChange(year, month); -// }, -// calendarSelect: (dateModel) { -// widget.calendarController.selectDateModel = dateModel; -// widget.calendarController.calendarSelect(dateModel); -// }, -// monthList: widget.calendarController.monthList, -// pageController: widget.calendarController.pageController, -// selectedDateList: -// widget.calendarController.selectedDateList, -// selectDateModel: -// widget.calendarController.selectDateModel, -// dayWidgetBuilder: -// widget.calendarController.dayWidgetBuilder, -// minSelectDate: DateModel() -// ..year = widget.calendarController.minSelectYear -// ..month = widget.calendarController.minSelectMonth -// ..day = widget.calendarController.minSelectDay, -// maxSelectDate: DateModel() -// ..year = widget.calendarController.maxSelectYear -// ..month = widget.calendarController.maxSelectMonth -// ..day = widget.calendarController.maxSelectDay, -// maxMultiSelectCount: -// widget.calendarController.maxMultiSelectCount, -// multiSelectOutOfRange: -// widget.calendarController.multiSelectOutOfRange, -// multiSelectOutOfSize: -// widget.calendarController.multiSelectOutOfSize, -// extraDataMap: widget.calendarController.extraDataMap, - ), - ) -// : Container( -// height: itemHeight, -// child: WeekViewPager( -// selectMode: widget.calendarController.selectMode, -// monthChange: (int year, int month) { -// widget.calendarController.monthChange(year, month); -// }, -// calendarSelect: (dateModel) { -// widget.calendarController.selectDateModel = dateModel; -// widget.calendarController.calendarSelect(dateModel); -// }, -// weekList: widget.calendarController.weekList, -// pageController: widget.calendarController.pageController, -// selectedDateList: -// widget.calendarController.selectedDateList, -// selectDateModel: -// widget.calendarController.selectDateModel, -// dayWidgetBuilder: -// widget.calendarController.dayWidgetBuilder, -// minSelectDate: DateModel() -// ..year = widget.calendarController.minSelectYear -// ..month = widget.calendarController.minSelectMonth -// ..day = widget.calendarController.minSelectDay, -// maxSelectDate: DateModel() -// ..year = widget.calendarController.maxSelectYear -// ..month = widget.calendarController.maxSelectMonth -// ..day = widget.calendarController.maxSelectDay, -// maxMultiSelectCount: -// widget.calendarController.maxMultiSelectCount, -// multiSelectOutOfRange: -// widget.calendarController.multiSelectOutOfRange, -// multiSelectOutOfSize: -// widget.calendarController.multiSelectOutOfSize, -// extraDataMap: widget.calendarController.extraDataMap, -// ), -// ), - ), + duration: Duration(milliseconds: 200), + height: expand ? totalHeight : itemHeight, + child: expand + ? Container( + height: totalHeight, + child: MonthViewPager(), + ) + : Container( + height: itemHeight, + child: WeekViewPager(), + ), + ), ], ), ); diff --git a/lib/widget/fast_click_widget.dart b/lib/widget/fast_click_widget.dart new file mode 100644 index 0000000..afc3f16 --- /dev/null +++ b/lib/widget/fast_click_widget.dart @@ -0,0 +1,32 @@ +import 'package:flutter/material.dart'; + +/** + * 防止快速点击 + */ +class FastClickWidget extends StatelessWidget { + final int between_time = 500; //默认两次点击间隔500ms内则点击无效 + + Function onTap; + Widget child; + + FastClickWidget({@required this.onTap, @required this.child}); + + int lastClickTime = 0; + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: () { + if (lastClickTime == 0 || + DateTime.now().millisecondsSinceEpoch - lastClickTime > + between_time) { + onTap(); + lastClickTime = DateTime.now().millisecondsSinceEpoch; + } else { + //间隔500ms内点击无效 + } + }, + child: child, + ); + } +} diff --git a/lib/widget/month_view.dart b/lib/widget/month_view.dart index 25016e3..83d3ad1 100644 --- a/lib/widget/month_view.dart +++ b/lib/widget/month_view.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:flutter_custom_calendar/CalendarProvider.dart'; +import 'package:flutter_custom_calendar/calendar_provider.dart'; import 'package:flutter_custom_calendar/configuration.dart'; import 'package:flutter_custom_calendar/constants/constants.dart'; import 'package:flutter_custom_calendar/model/date_model.dart'; @@ -10,32 +10,22 @@ import 'package:provider/provider.dart'; * 月视图,显示整个月的日子 */ class MonthView extends StatefulWidget { -// OnCalendarSelect onCalendarSelectListener; + final int year; + final int month; + final int day; -// Set selectedDateList; //被选中的日期 -// -// DateModel selectDateModel; //当前选择项,用于单选 -// -// DayWidgetBuilder dayWidgetBuilder; -// -// OnMultiSelectOutOfRange multiSelectOutOfRange; //多选超出指定范围 -// OnMultiSelectOutOfSize multiSelectOutOfSize; //多选超出限制个数 + final DateModel minSelectDate; + final DateModel maxSelectDate; - int year; - int month; - int day; + final Map extraDataMap; //自定义额外的数据 - DateModel minSelectDate; - DateModel maxSelectDate; - - Map extraDataMap; //自定义额外的数据 - - MonthView({ + const MonthView({ @required this.year, @required this.month, this.day, this.minSelectDate, this.maxSelectDate, + this.extraDataMap, }); @override @@ -82,7 +72,7 @@ class _MonthViewState extends State { CalendarConfiguration configuration = calendarProvider.calendarConfiguration; print( - "Consumer:calendarProvider.selectDateModel:${calendarProvider.selectDateModel}"); + "MonthView Consumer:calendarProvider.selectDateModel:${calendarProvider.selectDateModel}"); return new GridView.builder( physics: NeverScrollableScrollPhysics(), gridDelegate: new SliverGridDelegateWithFixedCrossAxisCount( @@ -108,6 +98,8 @@ class _MonthViewState extends State { return GestureDetector( onTap: () { print("GestureDetector onTap:$dateModel"); + print("!dateModel.isInRange:${!dateModel.isInRange}"); + //范围外不可点击 if (!dateModel.isInRange) { //多选回调 @@ -117,6 +109,8 @@ class _MonthViewState extends State { return; } + calendarProvider.lastClickDateModel = dateModel; + if (configuration.selectMode == Constants.MODE_MULTI_SELECT) { //多选,判断是否超过限制,超过范围 if (calendarProvider.selectedDateList.length == diff --git a/lib/widget/month_view_pager.dart b/lib/widget/month_view_pager.dart index 8347af0..77338b1 100644 --- a/lib/widget/month_view_pager.dart +++ b/lib/widget/month_view_pager.dart @@ -1,7 +1,8 @@ import 'package:flutter/material.dart'; -import 'package:flutter_custom_calendar/CalendarProvider.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/date_util.dart'; import 'package:flutter_custom_calendar/widget/month_view.dart'; import 'package:provider/provider.dart'; @@ -13,14 +14,50 @@ class MonthViewPager extends StatefulWidget { } class _MonthViewPagerState extends State { + CalendarProvider calendarProvider; + @override - void initState() {} + void 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)))); +// print("firstDayOfMonth:$firstDayOfMonth"); +// print("lastDayOfMonth:$lastDayOfMonth"); + + if ((dateModel.isAfter(firstDayOfMonth) || + dateModel.isSameWith(firstDayOfMonth)) && + dateModel.isBefore(lastDayOfMonth)) { + index = i; + break; + } + } +// print("monthList:$monthList"); +// print("当前月:index:$index"); + WidgetsBinding.instance.addPostFrameCallback((timeStamp) { + calendarProvider.calendarConfiguration.pageController.jumpToPage(index); + }); + } + + @override + void dispose() { + super.dispose(); + } @override Widget build(BuildContext context) { // 获取到当前的CalendarProvider对象,设置listen为false,不需要刷新 - CalendarProvider calendarProvider = - Provider.of(context, listen: false); + calendarProvider = Provider.of(context, listen: false); CalendarConfiguration configuration = calendarProvider.calendarConfiguration; @@ -35,13 +72,8 @@ class _MonthViewPagerState extends State { itemBuilder: (context, index) { DateModel dateModel = configuration.monthList[index]; return new MonthView( -// selectMode: configuration.selectMode, year: dateModel.year, month: dateModel.month, -// selectDateModel: calendarProvider.selectDateModel, -// selectedDateList: calendarProvider.selectedDateList, -// onCalendarSelectListener: configuration.calendarSelect, -// dayWidgetBuilder: configuration.dayWidgetBuilder, minSelectDate: DateModel.fromDateTime(DateTime( configuration.minSelectYear, configuration.minSelectMonth, @@ -50,10 +82,7 @@ class _MonthViewPagerState extends State { configuration.maxSelectYear, configuration.maxSelectMonth, configuration.maxSelectDay)), -// maxMultiSelectCount: configuration.maxMultiSelectCount, -// multiSelectOutOfRange: configuration.multiSelectOutOfRange, -// multiSelectOutOfSize: configuration.multiSelectOutOfSize, -// extraDataMap: configuration.extraDataMap, + extraDataMap: configuration.extraDataMap, ); }, itemCount: configuration.monthList.length, diff --git a/lib/widget/week_view.dart b/lib/widget/week_view.dart index f887016..d14d0f8 100644 --- a/lib/widget/week_view.dart +++ b/lib/widget/week_view.dart @@ -1,50 +1,31 @@ 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/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:provider/provider.dart'; /** * 周视图,只显示本周的日子 */ class WeekView extends StatefulWidget { - OnCalendarSelect onCalendarSelectListener; + final int year; + final int month; + final DateModel firstDayOfWeek; - Set selectedDateList; //被选中的日期 + final DateModel minSelectDate; + final DateModel maxSelectDate; - DateModel selectDateModel; //当前选择项,用于单选 + final Map extraDataMap; //自定义额外的数据 - DayWidgetBuilder dayWidgetBuilder; - - OnMultiSelectOutOfRange multiSelectOutOfRange; //多选超出指定范围 - OnMultiSelectOutOfSize multiSelectOutOfSize; //多选超出限制个数 - - int year; - int month; - int day; - - DateModel minSelectDate; - DateModel maxSelectDate; - - int selectMode; - int maxMultiSelectCount; - - Map extraDataMap; //自定义额外的数据 - - WeekView( + const WeekView( {@required this.year, @required this.month, - this.day, - this.onCalendarSelectListener, - this.dayWidgetBuilder, - this.selectedDateList, - this.selectDateModel, + this.firstDayOfWeek, this.minSelectDate, this.maxSelectDate, - this.selectMode, - this.multiSelectOutOfSize, - this.multiSelectOutOfRange, - this.maxMultiSelectCount, this.extraDataMap}); @override @@ -53,80 +34,88 @@ class WeekView extends StatefulWidget { class _WeekViewState extends State { List items; - DateModel selectDateModel; //当前选择项,用于单选 @override void initState() { super.initState(); - items=DateUtil.initCalendarForWeekView(2019, 9, DateTime.now(), 0); - + items = DateUtil.initCalendarForWeekView( + 2019, 9, widget.firstDayOfWeek.getDateTime(), 0, + minSelectDate: widget.minSelectDate, + maxSelectDate: widget.maxSelectDate, + extraDataMap: widget.extraDataMap); } @override Widget build(BuildContext context) { - - - return new GridView.builder( - physics: NeverScrollableScrollPhysics(), - gridDelegate: new SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 7, mainAxisSpacing: 10), - itemCount: 7, - itemBuilder: (context, index) { - DateModel dateModel = items[index]; - //判断是否被选择 - if (widget.selectMode == Constants.MODE_MULTI_SELECT) { - if (widget.selectedDateList.contains(dateModel)) { - dateModel.isSelected = true; - } else { - dateModel.isSelected = false; - } - } else { - if (selectDateModel == dateModel) { - dateModel.isSelected = true; + 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; + } } else { - dateModel.isSelected = false; - } - } - - return GestureDetector( - onTap: () { - //范围外不可点击 - if (!dateModel.isInRange) { - //多选回调 - if (widget.selectMode == Constants.MODE_MULTI_SELECT) { - widget.multiSelectOutOfRange(); - } - return; + if (calendarProvider.selectDateModel == dateModel) { + dateModel.isSelected = true; + } else { + dateModel.isSelected = false; } + } - if (widget.selectMode == Constants.MODE_MULTI_SELECT) { - //多选,判断是否超过限制,超过范围 - if (widget.selectedDateList.length == - widget.maxMultiSelectCount) { - widget.multiSelectOutOfSize(); + 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; } - - //多选也可以弄这些单选的代码 - selectDateModel = dateModel; - widget.selectDateModel = dateModel; - widget.onCalendarSelectListener(dateModel); - setState(() { - if (widget.selectedDateList.contains(dateModel)) { - widget.selectedDateList.remove(dateModel); - } else { - widget.selectedDateList.add(dateModel); + calendarProvider.lastClickDateModel = dateModel; + + if (configuration.selectMode == Constants.MODE_MULTI_SELECT) { + //多选,判断是否超过限制,超过范围 + if (calendarProvider.selectedDateList.length == + configuration.maxMultiSelectCount) { + configuration.multiSelectOutOfSize(); + return; } - }); - } else { - selectDateModel = dateModel; - widget.selectDateModel = dateModel; - widget.onCalendarSelectListener(dateModel); - setState(() {}); - } - }, - child: widget.dayWidgetBuilder(dateModel), - ); - }); + + //多选也可以弄这些单选的代码 + 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), + ); + }); + }); } } diff --git a/lib/widget/week_view_pager.dart b/lib/widget/week_view_pager.dart index 0274719..fe439df 100644 --- a/lib/widget/week_view_pager.dart +++ b/lib/widget/week_view_pager.dart @@ -1,88 +1,99 @@ 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/controller.dart'; import 'package:flutter_custom_calendar/model/date_model.dart'; import 'package:flutter_custom_calendar/widget/week_view.dart'; +import 'package:provider/provider.dart'; class WeekViewPager extends StatefulWidget { - final OnMonthChange monthChange; - - final OnCalendarSelect calendarSelect; - final DayWidgetBuilder dayWidgetBuilder; - OnMultiSelectOutOfRange multiSelectOutOfRange; //多选超出指定范围 - OnMultiSelectOutOfSize multiSelectOutOfSize; //多选超出限制个数 - - Set selectedDateList; //被选中的日期,用于多选 - DateModel selectDateModel; //当前选择项,用于单选 - - final List weekList; - PageController pageController; - - DateModel minSelectDate; - DateModel maxSelectDate; - - int selectMode; - int maxMultiSelectCount; - - Map extraDataMap; //自定义额外的数据 - - WeekViewPager( - {this.monthChange, - this.calendarSelect, - this.weekList, - this.pageController, - this.selectedDateList, - this.selectDateModel, - this.dayWidgetBuilder, - this.minSelectDate, - this.maxSelectDate, - this.selectMode, - this.maxMultiSelectCount, - this.multiSelectOutOfRange, - this.multiSelectOutOfSize, - this.extraDataMap}); + WeekViewPager(); @override _WeekViewPagerState createState() => _WeekViewPagerState(); } class _WeekViewPagerState extends State { - - int lastMonth;//上一个月份 + int lastMonth; //保存上一个月份,不然不知道月份发生了变化 + CalendarProvider calendarProvider; @override void initState() { -// lastMonth= + print("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"); + super.dispose(); } @override Widget build(BuildContext context) { + // 获取到当前的CalendarProvider对象,设置listen为false,不需要刷新 + CalendarProvider calendarProvider = + Provider.of(context, listen: false); + CalendarConfiguration configuration = + calendarProvider.calendarConfiguration; + return Container( child: PageView.builder( onPageChanged: (position) { - //月份的变化 - DateModel dateModel = widget.weekList[position]; - widget.monthChange(dateModel.year, dateModel.month); +// 周视图的变化 + DateModel firstDayOfWeek = configuration.weekList[position]; + int currentMonth = firstDayOfWeek.month; + if (lastMonth != currentMonth) { + configuration.monthChange( + firstDayOfWeek.year, firstDayOfWeek.month); + } +// DateModel dateModel = configuration.weekList[position]; +// configuration.monthChange(dateModel.year, dateModel.month); }, - controller: widget.pageController, + controller: configuration.weekController, itemBuilder: (context, index) { - DateModel dateModel = widget.weekList[index]; + DateModel dateModel = configuration.weekList[index]; return new WeekView( - selectMode: widget.selectMode, year: dateModel.year, month: dateModel.month, - selectDateModel: widget.selectDateModel, - selectedDateList: widget.selectedDateList, - onCalendarSelectListener: widget.calendarSelect, - dayWidgetBuilder: widget.dayWidgetBuilder, - minSelectDate: widget.minSelectDate, - maxSelectDate: widget.maxSelectDate, - maxMultiSelectCount: widget.maxMultiSelectCount, - multiSelectOutOfRange: widget.multiSelectOutOfRange, - multiSelectOutOfSize: widget.multiSelectOutOfSize, - extraDataMap: widget.extraDataMap, + 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, ); }, - itemCount: widget.weekList.length, + itemCount: configuration.weekList.length, ), ); } diff --git a/pubspec.yaml b/pubspec.yaml index 16ae204..52eb617 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -10,7 +10,7 @@ environment: dependencies: flutter: sdk: flutter - + provider: 3.0.0+1 dev_dependencies: flutter_test: sdk: flutter