diff --git a/README.md b/README.md index 2add2a6..0f36d93 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ Flutter上的一个日历控件,可以定制成自己想要的样子。 * 支持月份视图和星期视图的展示与切换联动 ## 近期修改 -### [1.0.0] - 2019/9/22 +### [1.0.0] - 2019/10/10 * 重构日历的代码,进行性能优化 * 创建configuration类,将配置的信息放到这里 * 引入provider状态管理,避免深层嵌套传递信息 @@ -123,6 +123,9 @@ extraDataMap | 自定义额外的数据| 默认为空Map,Map :-: | :-: | :-: weekBarItemWidgetBuilder | 创建顶部的weekbar | 默认样式 dayWidgetBuilder | 创建日历item | 默认样式 +verticalSpacing|日历item之间的竖直方向间距|默认10 +boxDecoration |整体的背景设置| +itemSize| 每个item的边长|默认是屏幕宽度/7| ### 事件监听的配置 diff --git a/example/lib/main.dart b/example/lib/main.dart index bb3056e..0428860 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -1,3 +1,4 @@ +import 'package:example/only_week_page.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'custom_sign_page.dart'; @@ -6,7 +7,7 @@ import 'default_style_page.dart'; import 'multi_select_style_page.dart'; import 'progress_style_page.dart'; -void main(){ +void main() { // debugProfileBuildsEnabled=true; // debugProfilePaintsEnabled=true; runApp(MyApp()); @@ -33,7 +34,10 @@ class MyApp extends StatelessWidget { ), "/custom_sign": (context) => CustomSignPage( title: "自定义额外数据,实现标记功能", - ) + ), + "/only_week_view": (context) => OnlyWeekPage( + title: "仅显示周视图", + ), }, title: 'Flutter Demo', theme: ThemeData( @@ -80,6 +84,12 @@ class HomePage extends StatelessWidget { }, child: new Text("自定义额外数据,实现标记功能"), ), + new RaisedButton( + onPressed: () { + Navigator.pushNamed(context, "/only_week_view"); + }, + child: new Text("仅显示周视图"), + ), ], ), ), diff --git a/example/lib/multi_select_style_page.dart b/example/lib/multi_select_style_page.dart index 10582f8..332b9de 100644 --- a/example/lib/multi_select_style_page.dart +++ b/example/lib/multi_select_style_page.dart @@ -43,13 +43,13 @@ class _MultiSelectStylePageState extends State { controller.addOnCalendarSelectListener((dateModel) { //刷新选择的时间 selectText.value = - "单选模式\n选中的时间:\n${controller.getSingleSelectCalendar()}"; + "多选模式\n选中的时间:\n${controller.getMultiSelectCalendar().join("\n")}"; }); text = new ValueNotifier("${DateTime.now().year}年${DateTime.now().month}月"); selectText = new ValueNotifier( - "单选模式\n选中的时间:\n${controller.getSingleSelectCalendar()}"); + "多选模式\n选中的时间:\n${controller.getSingleSelectCalendar()}"); } @override diff --git a/example/lib/only_week_page.dart b/example/lib/only_week_page.dart new file mode 100644 index 0000000..3a29296 --- /dev/null +++ b/example/lib/only_week_page.dart @@ -0,0 +1,101 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_custom_calendar/flutter_custom_calendar.dart'; + +/** + * 默认风格+单选 + */ +class OnlyWeekPage extends StatefulWidget { + OnlyWeekPage({Key key, this.title}) : super(key: key); + + final String title; + + @override + _OnlyWeekPageState createState() => _OnlyWeekPageState(); +} + +class _OnlyWeekPageState extends State { + ValueNotifier text; + ValueNotifier selectText; + + CalendarController controller; + + @override + void initState() { + DateTime now = DateTime.now(); + controller = new CalendarController( + minYear: now.year, + minYearMonth: now.month - 2, + maxYear: now.year, + maxYearMonth: now.month + 1, + showMode: Constants.MODE_SHOW_ONLY_WEEK); + + controller.addMonthChangeListener( + (year, month) { + text.value = "$year年$month月"; + }, + ); + + controller.addOnCalendarSelectListener((dateModel) { + //刷新选择的时间 + selectText.value = + "单选模式\n选中的时间:\n${controller.getSingleSelectCalendar()}"; + }); + + text = new ValueNotifier("${DateTime.now().year}年${DateTime.now().month}月"); + + selectText = new ValueNotifier( + "单选模式\n选中的时间:\n${controller.getSingleSelectCalendar()}"); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text(widget.title), + ), + body: new Container( + child: new Column( + children: [ + new Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + new IconButton( + icon: Icon(Icons.navigate_before), + onPressed: () { +// controller.moveToPreviousMonth(); + controller.previousPage(); + }), + ValueListenableBuilder( + valueListenable: text, + builder: (context, value, child) { + return new Text(text.value); + }), + new IconButton( + icon: Icon(Icons.navigate_next), + onPressed: () { +// controller.moveToNextMonth(); + controller.nextPage(); + }), + ], + ), + CalendarViewWidget( + calendarController: controller, + ), + ValueListenableBuilder( + valueListenable: selectText, + builder: (context, value, child) { + return new Text(selectText.value); + }), + ], + ), + ), + floatingActionButton: FloatingActionButton( + onPressed: () { + controller.toggleExpandStatus(); + }, + tooltip: 'Increment', + child: Icon(Icons.add), + ), // This trailing comma makes auto-formatting nicer for build methods. + ); + } +} diff --git a/lib/calendar_provider.dart b/lib/calendar_provider.dart index 9ad1a00..4d30ca6 100644 --- a/lib/calendar_provider.dart +++ b/lib/calendar_provider.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_custom_calendar/cache_data.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'; import 'package:flutter_custom_calendar/utils/LogUtil.dart'; import 'package:flutter_custom_calendar/utils/date_util.dart'; @@ -78,7 +79,7 @@ class CalendarProvider extends ChangeNotifier { return index + 1; } - ValueNotifier expandStatus = ValueNotifier(true); //当前展开状态 + ValueNotifier expandStatus; //当前展开状态 //配置类也放这里吧,这样的话,所有子树,都可以拿到配置的信息 CalendarConfiguration calendarConfiguration; @@ -98,12 +99,17 @@ class CalendarProvider extends ChangeNotifier { ? selectDateModel : DateModel.fromDateTime(DateTime.now()) ..day = 15; + if (calendarConfiguration.showMode == Constants.MODE_SHOW_ONLY_WEEK) { + expandStatus = ValueNotifier(false); + } else { + expandStatus = ValueNotifier(true); + } } //退出的时候,清除数据 void clearData() { LogUtil.log(TAG: this.runtimeType, message: "CalendarProvider clearData"); - CacheData.instance.clearData(); + CacheData.getInstance().clearData(); selectedDateList.clear(); selectDateModel = null; calendarConfiguration = null; diff --git a/lib/controller.dart b/lib/controller.dart index fc4a984..a24d8f2 100644 --- a/lib/controller.dart +++ b/lib/controller.dart @@ -83,36 +83,6 @@ class CalendarController { }).toSet()); } - //初始化pageController,initialPage默认是当前时间对于的页面 - int initialPage = 0; - int nowMonthIndex = 0; - monthList.clear(); - for (int i = minYear; i <= maxYear; i++) { - for (int j = 1; j <= 12; j++) { - if (i == minYear && j < minYearMonth) { - continue; - } - if (i == maxYear && j > maxYearMonth) { - continue; - } - DateModel dateModel = new DateModel(); - dateModel.year = i; - dateModel.month = j; - - //如果没有配置当前时间,设置成当前的时间 - if (nowYear == -1 || nowMonth == -1) { - nowYear = DateTime.now().year; - nowMonth = DateTime.now().month; - } - if (i == nowYear && j == nowMonth) { - initialPage = nowMonthIndex; - } - monthList.add(dateModel); - nowMonthIndex++; - } - } - this.monthController = - new PageController(initialPage: initialPage, keepPage: true); LogUtil.log( TAG: this.runtimeType, message: "start:${DateModel.fromDateTime(DateTime( @@ -122,35 +92,86 @@ class CalendarController { maxYear, maxYearMonth, ))}"); - LogUtil.log( - TAG: this.runtimeType, - message: - "初始化月份视图的信息:一共有${monthList.length}个月,initialPage为${nowMonthIndex}"); - //计算一共多少周 - //计算方法:第一天是周几,最后一天是周几,中间的天数/7后加上2就是结果了 - int initialWeekPage = 0; - int nowWeekIndex = 0; - weekList.clear(); + if (showMode == Constants.MODE_SHOW_ONLY_MONTH || + showMode == Constants.MODE_SHOW_WEEK_AND_MONTH) { + //初始化pageController,initialPage默认是当前时间对于的页面 + int initialPage = 0; + int nowMonthIndex = 0; + monthList.clear(); + for (int i = minYear; i <= maxYear; i++) { + for (int j = 1; j <= 12; j++) { + if (i == minYear && j < minYearMonth) { + continue; + } + if (i == maxYear && j > maxYearMonth) { + continue; + } + DateModel dateModel = new DateModel(); + dateModel.year = i; + dateModel.month = j; + + //如果没有配置当前时间,设置成当前的时间 + if (nowYear == -1 || nowMonth == -1) { + nowYear = DateTime.now().year; + nowMonth = DateTime.now().month; + } + if (i == nowYear && j == nowMonth) { + initialPage = nowMonthIndex; + } + monthList.add(dateModel); + nowMonthIndex++; + } + } + this.monthController = + new PageController(initialPage: initialPage, keepPage: true); - DateTime firstDayOfMonth = DateTime(minYear, minYearMonth, 1); - //计算第一个星期的第一天的日期 - DateTime firstWeekDate = - firstDayOfMonth.add(Duration(days: -(firstDayOfMonth.weekday - 1))); - - DateTime lastDay = DateTime(maxYear, maxYearMonth, - DateUtil.getMonthDaysCount(maxYear, maxYearMonth)); - for (DateTime dateTime = firstWeekDate; - !dateTime.isAfter(lastDay); - dateTime = dateTime.add(Duration(days: 7))) { - DateModel dateModel = DateModel.fromDateTime(dateTime); - weekList.add(dateModel); + LogUtil.log( + TAG: this.runtimeType, + message: + "初始化月份视图的信息:一共有${monthList.length}个月,initialPage为${nowMonthIndex}"); + } + + if (showMode == Constants.MODE_SHOW_ONLY_WEEK || + showMode == Constants.MODE_SHOW_WEEK_AND_MONTH) { + //计算一共多少周 + //计算方法:第一天是周几,最后一天是周几,中间的天数/7后加上2就是结果了 + int initialWeekPage = 0; + int nowWeekIndex = 0; + weekList.clear(); + //如果没有配置当前时间,设置成当前的时间 + if (nowYear == -1 || nowMonth == -1) { + nowYear = DateTime.now().year; + nowMonth = DateTime.now().month; + } + DateTime nowTime = new DateTime(nowYear, nowMonth, 15); + DateTime firstDayOfMonth = DateTime(minYear, minYearMonth, 1); + //计算第一个星期的第一天的日期 + DateTime firstWeekDate = + firstDayOfMonth.add(Duration(days: -(firstDayOfMonth.weekday - 1))); + + DateTime lastDay = DateTime(maxYear, maxYearMonth, + DateUtil.getMonthDaysCount(maxYear, maxYearMonth)); + int temp = -1; + for (DateTime dateTime = firstWeekDate; + !dateTime.isAfter(lastDay); + dateTime = dateTime.add(Duration(days: 7))) { + DateModel dateModel = DateModel.fromDateTime(dateTime); + weekList.add(dateModel); + print("nowTime.isBefore(dateTime)"); + print("$nowTime,,,,$dateTime"); + + if (nowTime.isAfter(dateTime)) { + temp++; + } + } + initialWeekPage = temp; + LogUtil.log( + TAG: this.runtimeType, + message: + "初始化星期视图的信息:一共有${weekList.length}个星期,initialPage为${initialWeekPage}"); + this.weekController = new PageController(initialPage: initialWeekPage); } - this.weekController = new PageController(); - LogUtil.log( - TAG: this.runtimeType, - message: - "初始化星期视图的信息:一共有${weekList.length}个星期,initialPage为${initialWeekPage}"); calendarConfiguration.monthList = monthList; calendarConfiguration.weekList = weekList; @@ -442,12 +463,11 @@ class CalendarController { } //清除数据 - void clearData(){ + void clearData() { monthList.clear(); weekList.clear(); calendarProvider.clearData(); } - } /** diff --git a/lib/widget/calendar_view.dart b/lib/widget/calendar_view.dart index 605340c..d04cd0f 100644 --- a/lib/widget/calendar_view.dart +++ b/lib/widget/calendar_view.dart @@ -54,13 +54,15 @@ class _CalendarViewWidgetState extends State { //外部可以自定义背景设置 decoration: widget.boxDecoration, //使用const,保证外界的setState不会刷新日历这个widget - child: const CalendarContainer()), + child: CalendarContainer(widget.calendarController)), ); } } class CalendarContainer extends StatefulWidget { - const CalendarContainer(); + final CalendarController calendarController; + + const CalendarContainer(this.calendarController); @override CalendarContainerState createState() => CalendarContainerState(); @@ -121,6 +123,28 @@ class CalendarContainerState extends State }); }); } + + widget.calendarController.addMonthChangeListener((year, month) { + if (widget.calendarController.calendarProvider.calendarConfiguration + .showMode != + Constants.MODE_SHOW_ONLY_WEEK) { + //月份切换的时候,如果高度发生变化的话,需要setState使高度整体自适应 + int lineCount = DateUtil.getMonthViewLineCount(year, month); + double newHeight = itemHeight * lineCount + + calendarProvider.calendarConfiguration.verticalSpacing * + (lineCount - 1); + if (totalHeight.toInt() != newHeight.toInt()) { + LogUtil.log( + TAG: this.runtimeType, + message: "totalHeight:$totalHeight,newHeight:$newHeight"); + + LogUtil.log(TAG: this.runtimeType, message: "月份视图高度发生变化"); + setState(() { + totalHeight = newHeight; + }); + } + } + }); } @override @@ -134,40 +158,10 @@ class CalendarContainerState extends State //暂时先这样写死,提前计算布局的高度,不然会出现问题:a horizontal viewport was given an unlimited amount of I/flutter ( 6759): vertical space in which to expand. 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)), -// ); - + if (totalHeight == null) { + totalHeight = itemHeight * 6 + + calendarProvider.calendarConfiguration.verticalSpacing * (6 - 1); + } return Container( width: itemHeight * 7, child: new Column( @@ -182,7 +176,6 @@ class CalendarContainerState extends State duration: Duration(milliseconds: 500), height: expand ? totalHeight : itemHeight, child: IndexedStack( -// overflow: Overflow.visible, index: index, children: widgets, )), diff --git a/lib/widget/month_view.dart b/lib/widget/month_view.dart index 120eebb..1d0c85c 100644 --- a/lib/widget/month_view.dart +++ b/lib/widget/month_view.dart @@ -194,12 +194,12 @@ class ItemContainerState extends State { return; } - configuration.calendarSelect(dateModel); if (calendarProvider.selectedDateList.contains(dateModel)) { calendarProvider.selectedDateList.remove(dateModel); } else { calendarProvider.selectedDateList.add(dateModel); } + configuration.calendarSelect(dateModel); //多选也可以弄这些单选的代码 calendarProvider.selectDateModel = dateModel;