From d0b0d88ca5fd67362005951dd46594aba880b471 Mon Sep 17 00:00:00 2001 From: LXD312569496 <450468291@qq.com> Date: Thu, 31 Oct 2019 17:58:31 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=87=E6=A1=A3=E4=BF=AE=E6=94=B9=EF=BC=8C?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- API.md | 318 +++++++++++++++++++++++ example/lib/blue_style_page.dart | 24 +- example/lib/custom_sign_page.dart | 13 +- example/lib/custom_style_page.dart | 15 +- example/lib/default_style_page.dart | 2 +- example/lib/main.dart | 21 +- example/lib/multi_select_style_page.dart | 26 +- example/lib/only_week_page.dart | 2 +- example/lib/progress_style_page.dart | 18 +- example/lib/red_style_page.dart | 236 +++++++++++++++++ lib/calendar_provider.dart | 22 +- lib/configuration.dart | 2 +- lib/constants/constants.dart | 2 +- lib/controller.dart | 50 ++-- lib/utils/lunar_util.dart | 6 +- lib/widget/calendar_view.dart | 34 ++- lib/widget/default_week_bar.dart | 2 +- lib/widget/month_view.dart | 6 +- lib/widget/week_view.dart | 2 +- 19 files changed, 694 insertions(+), 107 deletions(-) create mode 100644 API.md create mode 100644 example/lib/red_style_page.dart diff --git a/API.md b/API.md new file mode 100644 index 0000000..4c2cd88 --- /dev/null +++ b/API.md @@ -0,0 +1,318 @@ + +## 主要Api文档 + +### 配置日历的UI + +日历UI相关的配置是在CalendarViewWidget的构造函数里面进行配置就行了。 +``` + CalendarViewWidget( + {Key key, + this.dayWidgetBuilder = defaultCustomDayWidget, + this.weekBarItemWidgetBuilder = defaultWeekBarWidget, + @required this.calendarController, + this.boxDecoration, + this.padding = EdgeInsets.zero, + this.margin = EdgeInsets.zero, + this.verticalSpacing = 10, + this.itemSize}) + : super(key: key); +``` +#### 参数说明 + +属性 | 含义 | 默认值 +:-: | :-: | :-: +weekBarItemWidgetBuilder | 创建顶部的weekbar | 默认样式 +dayWidgetBuilder | 创建日历item | 默认样式 +verticalSpacing|日历item之间的竖直方向间距|默认10 +boxDecoration |整体的背景设置|默认为空 +itemSize| 每个item的边长|手机默认是屏幕宽度/7,网页默认屏幕高度/7| +padding|日历的padding |默认为EdgeInsets.zero +margin| 日历的padding|默认为EdgeInsets.zero + + + +### 配置Controller +两个作用: +一个是显示日历所需要的相关数据,是在controller里面进行配置的。 +一个是可以利用controller添加事件监听,使用controller进行操作日历 + + +``` + //构造函数 + CalendarController( + {int selectMode = CalendarConstants.MODE_SINGLE_SELECT, + int showMode = CalendarConstants.MODE_SHOW_ONLY_MONTH, + int minYear = 1971, + int maxYear = 2055, + int minYearMonth = 1, + int maxYearMonth = 12, + int nowYear, + int nowMonth, + int minSelectYear = 1971, + int minSelectMonth = 1, + int minSelectDay = 1, + int maxSelectYear = 2055, + int maxSelectMonth = 12, + int maxSelectDay = 30, + Set selectedDateTimeList = EMPTY_SET, + DateModel selectDateModel, + int maxMultiSelectCount = 9999, + Map extraDataMap = EMPTY_MAP}) +``` + +#### 通用参数说明 + +属性 | 含义 | 默认值 +:-: | :-: | :-: +selectMode | 选择模式,表示单选或者多选 | 默认是单选
static const int MODE_SINGLE_SELECT = 1;
static const int MODE_MULTI_SELECT = 2; +showMode|展示模式| 默认是只展示月视图
static const int MODE_SHOW_ONLY_MONTH=1;//仅支持月视图
static const int MODE_SHOW_ONLY_WEEK=2;//仅支持星期视图
static const int MODE_SHOW_WEEK_AND_MONTH=3;//支持两种视图,先显示周视图
static const int MODE_SHOW_MONTH_AND_WEEK=4;//支持两种视图,先显示月视图 +minYear | 日历显示的最小年份| 1971 +maxYear | 日历显示的最大年份| 2055 +minYearMonth | 日历显示的最小年份的月份| 1 +maxYearMonth | 日历显示的最大年份的月份| 12 +nowYear | 日历显示的当前的年份| -1 +nowMonth | 日历显示的当前的月份| -1 +minSelectYear | 可以选择的最小年份| 1971 +minSelectMonth | 可以选择的最小年份的月份| 1 +minSelectDay | 可以选择的最小月份的日子| 1 +maxSelectYear | 可以选择的最大年份| 2055 +maxSelectMonth | 可以选择的最大年份的月份| 12 +maxSelectDay | 可以选择的最大月份的日子| 30,注意:不能超过对应月份的总天数 +selectedDateList | 被选中的日期,用于多选| 默认为空Set, Set selectedDateList = new Set() +selectDateModel | 当前选择项,用于单选| 默认为空 +maxMultiSelectCount | 多选,最多选多少个| hhh +extraDataMap | 自定义额外的数据| 默认为空Map,Map extraDataMap = new Map() + + +#### 给controller添加事件监听 + +方法 | 含义 | 默认值 +:-: | :-: | :-: +void addMonthChangeListener(OnMonthChange listener) | 月份切换事件 | +void addOnCalendarSelectListener(OnCalendarSelect listener) | 点击选择事件 | +void addOnMultiSelectOutOfRangeListener(OnMultiSelectOutOfRange listener) | 多选超出指定范围 | +void addOnMultiSelectOutOfSizeListener(OnMultiSelectOutOfSize listener) | 多选超出限制个数 | +void addExpandChangeListener(ValueChanged expandChange)|监听日历的展开收缩状态| + +#### 利用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 moveToNextYear()|切换到下一年| +void moveToPreviousYear()|切换到上一年| +void moveToNextMonth()|切换到下一个月份| +void moveToPreviousMonth()|切换到上一个月份| +void toggleExpandStatus()|切换展开状态| +void changeExtraData(Map newMap)|修改自定义的额外数据并刷新日历| + + +#### 利用controller来获取当前日历的状态和数据 + +方法 | 含义 | 默认值 +:-: | :-: | :-: +DateTime getCurrentMonth()|获取当前的月份| +Set getMultiSelectCalendar()|获取被选中的日期,多选| +DateModel getSingleSelectCalendar()|获取被选中的日期,单选| + + + +### 如何自定义UI + +包括自定义WeekBar、自定义日历Item,默认使用的都是DefaultXXXWidget。 + +只要继承对应的Base类,实现相应的方法,然后只需要在配置Controller的时候,实现相应的Builder方法就可以了。 +``` +//支持自定义绘制 +DayWidgetBuilder dayWidgetBuilder; //创建日历item +WeekBarItemWidgetBuilder weekBarItemWidgetBuilder; //创建顶部的weekbar +``` +#### 自定义WeekBar +第一种做法,继承BaseWeekBar,重写getWeekBarItem(index)方法就可以。随便你怎么实现,只需要返回一个Widget就可以了。 +``` +class DefaultWeekBar extends BaseWeekBar { + const DefaultWeekBar({Key key}) : super(key: key); + @override + Widget getWeekBarItem(int index) { + /** + * 自定义Widget + */ + return new Container( + height: 40, + alignment: Alignment.center, + child: new Text( + Constants.WEEK_LIST[index], + style: topWeekTextStyle, + ), + ); + } +} +``` +第二种做法,你也可以直接重写build方法,进行更加的自定义绘制。 + +``` +class CustomStyleWeekBarItem extends BaseWeekBar { + List weekList = ["mo", "tu", "we", "th", "fr", "sa", "su"]; + + //可以直接重写build方法,weekbar底部添加下划线 + @override + Widget build(BuildContext context) { + List children = List(); + + var items = getWeekDayWidget(); + children.add(Row( + children: items, + )); + children.add(Divider( + color: Colors.grey, + )); + return Column( + children: children, + ); + } + + @override + Widget getWeekBarItem(int index) { + return new Container( + margin: EdgeInsets.only(top: 10, bottom: 10), + child: new Center( + child: new Text( + weekList[index], + style: + TextStyle(fontWeight: FontWeight.w700, color: Color(0xffC5BCDC)), + ), + ), + ); + } +} +``` + + +#### 自定义日历Item: +提供两种方法,一种是利用组合widget的方式来创建,一种是利用Canvas来自定义绘制Item。最后只需要在CalendarController的构造参数中进行配置就可以了。 +* 利用组合widget的方式来创建:继承BaseCombineDayWidget,重写getNormalWidget(DateModel dateModel) +和getSelectedWidget(DateModel dateModel)就可以了,返回对应的widget就行。 +``` +class DefaultCombineDayWidget extends BaseCombineDayWidget { + DefaultCombineDayWidget(DateModel dateModel) : super(dateModel); + + @override + Widget getNormalWidget(DateModel dateModel) { + //实现默认状态下的UI + } + + @override + Widget getSelectedWidget(DateModel dateModel) { + //绘制被选中的UI + } +} +``` + + +* 利用Canvas来自定义绘制,继承BaseCustomDayWidget,重写drawNormal和drawSelected的两个方法就可以了,利用canvas自己绘制Item。 + +``` +class DefaultCustomDayWidget extends BaseCustomDayWidget { + DefaultCustomDayWidget(DateModel dateModel) : super(dateModel); + @override + void drawNormal(DateModel dateModel, Canvas canvas, Size size) { + //实现默认状态下的UI + defaultDrawNormal(dateModel, canvas, size); + } + @override + void drawSelected(DateModel dateModel, Canvas canvas, Size size) { + //绘制被选中的UI + defaultDrawSelected(dateModel, canvas, size); + } +} +``` + +### 根据实际场景,自定义额外的数据extraData + +#### 实现进度条样式的日历 + +我们可以自定义每个item的进度条数据,保存到map中,最后赋值给controller的extraDataMap。 +``` + //外部处理每个dateModel所对应的进度 + Map progressMap = { + DateModel.fromDateTime(temp.add(Duration(days: 1))): 0, + DateModel.fromDateTime(temp.add(Duration(days: 2))): 20, + DateModel.fromDateTime(temp.add(Duration(days: 3))): 40, + DateModel.fromDateTime(temp.add(Duration(days: 4))): 60, + DateModel.fromDateTime(temp.add(Duration(days: 5))): 80, + DateModel.fromDateTime(temp.add(Duration(days: 6))): 100, + }; + //创建CalendarController对象的时候,将extraDataMap赋值就行了 + new CalendarController( + extraDataMap: progressMap) + //绘制DayWidget的时候,可以直接从dateModel的extraData对象中拿到想要的数据 + int progress = dateModel.extraData; +``` + +#### 实现自定义各种标记的日历 +``` + //外部处理每个dateModel所对应的标记 + Map customExtraData = { + DateModel.fromDateTime(DateTime.now().add(Duration(days: -1))): "假", + DateModel.fromDateTime(DateTime.now().add(Duration(days: -2))): "游", + DateModel.fromDateTime(DateTime.now().add(Duration(days: -3))): "事", + DateModel.fromDateTime(DateTime.now().add(Duration(days: -4))): "班", + DateModel.fromDateTime(DateTime.now().add(Duration(days: -5))): "假", + DateModel.fromDateTime(DateTime.now().add(Duration(days: -6))): "游", + DateModel.fromDateTime(DateTime.now().add(Duration(days: 2))): "游", + DateModel.fromDateTime(DateTime.now().add(Duration(days: 3))): "事", + DateModel.fromDateTime(DateTime.now().add(Duration(days: 4))): "班", + DateModel.fromDateTime(DateTime.now().add(Duration(days: 5))): "假", + DateModel.fromDateTime(DateTime.now().add(Duration(days: 6))): "游", + DateModel.fromDateTime(DateTime.now().add(Duration(days: 7))): "事", + DateModel.fromDateTime(DateTime.now().add(Duration(days: 8))): "班", + }; + //创建CalendarController对象的时候,将extraDataMap赋值就行了 + new CalendarController( + extraDataMap: customExtraData) + //绘制DayWidget的时候,可以直接从dateModel的extraData对象中拿到想要的数据 + String data = dateModel.extraData; +``` + +#### 手动修改自定义的数据 +当自定义的数据发生变化的时候,可以使用controller的changeExtraData(Map newMap)方法, +日历会自动刷新,根据新的额外数据进行绘制。 +``` + //可以动态修改extraDataMap + void changeExtraData(Map newMap) { + this.calendarConfiguration.extraDataMap = newMap; + this.calendarProvider.generation.value++; + } +``` + +### DateModel实体类 +日历所用的日期的实体类DateModel,有下面这些属性。可以在自定义绘制DayWidget的时候,根据相应的属性,进行判断后,绘制相应的UI。 + +属性|含义|类型|默认值 +:-: | :-: | :-: |:-: +year|年份|int| +month|月份|int| +day|日期|int|默认为1 +lunarYear|农历年份|int| +lunarMonth|农历月份|int| +lunarDay|农历日期|int| +lunarString|农历字符串|String| +solarTerm|24节气|String| +gregorianFestival|gregorianFestival|String| +traditionFestival|传统农历节日|String| +isCurrentDay|是否是今天|bool|false +isLeapYear|是否是闰年|bool|false +isWeekend|是否是周末|bool|false +isInRange|是否在范围内,比如可以实现在某个范围外,设置置灰的功能|bool|false +isSelected|是否被选中,用来实现一些标记或者选择功能|bool|false +extraData|自定义的额外数据|Object|默认为空 +isCurrentMonth|是否是当前月份|bool| + + +方法|含义| +:-: | :-: | +DateTime getDateTime()|将DateModel转化成DateTime +DateModel fromDateTime(DateTime dateTime)|根据DateTime创建对应的model,并初始化农历和传统节日等信息 +bool operator ==(Object other)|重写==方法,可以判断两个dateModel是否是同一天 \ No newline at end of file diff --git a/example/lib/blue_style_page.dart b/example/lib/blue_style_page.dart index ab4a71f..297c2f0 100644 --- a/example/lib/blue_style_page.dart +++ b/example/lib/blue_style_page.dart @@ -3,9 +3,7 @@ import 'package:flutter_custom_calendar/flutter_custom_calendar.dart'; import 'package:flutter_custom_calendar/style/style.dart'; import 'package:random_pk/random_pk.dart'; -/** - * 自定义一些额外的数据,实现标记功能 - */ + class BlueStylePage extends StatefulWidget { BlueStylePage({Key key, this.title}) : super(key: key); @@ -26,13 +24,8 @@ class _BlueStylePageState extends State { @override void initState() { controller = new CalendarController( - weekBarItemWidgetBuilder: () { - return CustomStyleWeekBarItem(); - }, - dayWidgetBuilder: (dateModel) { - return CustomStyleDayWidget(dateModel); - }, - showMode: Constants.MODE_SHOW_MONTH_AND_WEEK, + + showMode: CalendarConstants.MODE_SHOW_MONTH_AND_WEEK, extraDataMap: customExtraData); controller.addMonthChangeListener( @@ -56,6 +49,12 @@ class _BlueStylePageState extends State { @override Widget build(BuildContext context) { var calendarWidget = CalendarViewWidget( + weekBarItemWidgetBuilder: () { + return CustomStyleWeekBarItem(); + }, + dayWidgetBuilder: (dateModel) { + return CustomStyleDayWidget(dateModel); + }, calendarController: controller, boxDecoration: BoxDecoration( borderRadius: BorderRadius.only( @@ -126,7 +125,10 @@ class _BlueStylePageState extends State { ValueListenableBuilder( valueListenable: selectText, builder: (context, value, child) { - return new Text(selectText.value); + return Padding( + padding: const EdgeInsets.all(20.0), + child: new Text(selectText.value), + ); }), ], ), diff --git a/example/lib/custom_sign_page.dart b/example/lib/custom_sign_page.dart index 74ad880..b4df94c 100644 --- a/example/lib/custom_sign_page.dart +++ b/example/lib/custom_sign_page.dart @@ -44,12 +44,7 @@ class _CustomSignPageState extends State { @override void initState() { controller = new CalendarController( - weekBarItemWidgetBuilder: () { - return CustomStyleWeekBarItem(); - }, - dayWidgetBuilder: (dateModel) { - return CustomStyleDayWidget(dateModel); - }, + extraDataMap: customExtraData); controller.addMonthChangeListener( @@ -101,6 +96,12 @@ class _CustomSignPageState extends State { ), CalendarViewWidget( calendarController: controller, + weekBarItemWidgetBuilder: () { + return CustomStyleWeekBarItem(); + }, + dayWidgetBuilder: (dateModel) { + return CustomStyleDayWidget(dateModel); + }, ), ValueListenableBuilder( valueListenable: selectText, diff --git a/example/lib/custom_style_page.dart b/example/lib/custom_style_page.dart index 711c058..6f587ca 100644 --- a/example/lib/custom_style_page.dart +++ b/example/lib/custom_style_page.dart @@ -21,11 +21,7 @@ class _CustomStylePageState extends State { @override void initState() { - controller = new CalendarController(weekBarItemWidgetBuilder: () { - return CustomStyleWeekBarItem(); - }, dayWidgetBuilder: (dateModel) { - return CustomStyleDayWidget(dateModel); - }); + controller = new CalendarController(); controller.addMonthChangeListener( (year, month) { @@ -75,8 +71,13 @@ class _CustomStylePageState extends State { ], ), CalendarViewWidget( - calendarController: controller, - ), + calendarController: controller, + weekBarItemWidgetBuilder: () { + return CustomStyleWeekBarItem(); + }, + dayWidgetBuilder: (dateModel) { + return CustomStyleDayWidget(dateModel); + }), ValueListenableBuilder( valueListenable: selectText, builder: (context, value, child) { diff --git a/example/lib/default_style_page.dart b/example/lib/default_style_page.dart index 39945b9..585be29 100644 --- a/example/lib/default_style_page.dart +++ b/example/lib/default_style_page.dart @@ -27,7 +27,7 @@ class _DefaultStylePageState extends State { minYearMonth: now.month - 5, maxYear: now.year, maxYearMonth: now.month + 5, - showMode: Constants.MODE_SHOW_MONTH_AND_WEEK); + showMode: CalendarConstants.MODE_SHOW_MONTH_AND_WEEK); controller.addMonthChangeListener( (year, month) { diff --git a/example/lib/main.dart b/example/lib/main.dart index 4bcbd68..7f579b1 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -1,4 +1,5 @@ import 'package:example/only_week_page.dart'; +import 'package:example/red_style_page.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'blue_style_page.dart'; @@ -40,9 +41,8 @@ class MyApp extends StatelessWidget { "/only_week_view": (context) => OnlyWeekPage( title: "仅显示周视图", ), - "/blue_style_page":(context)=>BlueStylePage( - title:"蓝色背景Demo" - ) + "/blue_style_page": (context) => BlueStylePage(title: "蓝色背景Demo"), + "/red_style_page": (context) => RedStylePage(title: "蓝色背景Demo"), }, title: 'Flutter Demo', theme: ThemeData( @@ -95,9 +95,18 @@ class HomePage extends StatelessWidget { }, child: new Text("仅显示周视图"), ), - new RaisedButton(onPressed: (){ - Navigator.pushNamed(context, "/blue_style_page"); - },child: new Text("蓝色Demo"),) + new RaisedButton( + onPressed: () { + Navigator.pushNamed(context, "/blue_style_page"); + }, + child: new Text("蓝色Demo"), + ), + new RaisedButton( + onPressed: () { + Navigator.pushNamed(context, "/red_style_page"); + }, + child: new Text("红色Demo"), + ) ], ), ), diff --git a/example/lib/multi_select_style_page.dart b/example/lib/multi_select_style_page.dart index 332b9de..dfabfb1 100644 --- a/example/lib/multi_select_style_page.dart +++ b/example/lib/multi_select_style_page.dart @@ -22,17 +22,12 @@ class _MultiSelectStylePageState extends State { @override void initState() { controller = new CalendarController( - selectMode: Constants.MODE_MULTI_SELECT, - maxMultiSelectCount: 5, - minSelectYear: 2019, - minSelectMonth: 5, - minSelectDay: 20, - weekBarItemWidgetBuilder: () { - return CustomStyleWeekBarItem(); - }, - dayWidgetBuilder: (dateModel) { - return CustomStyleDayWidget(dateModel); - }); + selectMode: CalendarConstants.MODE_MULTI_SELECT, + maxMultiSelectCount: 5, + minSelectYear: 2019, + minSelectMonth: 5, + minSelectDay: 20, + ); controller.addMonthChangeListener( (year, month) { @@ -82,8 +77,13 @@ class _MultiSelectStylePageState extends State { ], ), CalendarViewWidget( - calendarController: controller, - ), + calendarController: controller, + weekBarItemWidgetBuilder: () { + return CustomStyleWeekBarItem(); + }, + dayWidgetBuilder: (dateModel) { + return CustomStyleDayWidget(dateModel); + }), ValueListenableBuilder( valueListenable: selectText, builder: (context, value, child) { diff --git a/example/lib/only_week_page.dart b/example/lib/only_week_page.dart index 3a29296..c9af7d3 100644 --- a/example/lib/only_week_page.dart +++ b/example/lib/only_week_page.dart @@ -27,7 +27,7 @@ class _OnlyWeekPageState extends State { minYearMonth: now.month - 2, maxYear: now.year, maxYearMonth: now.month + 1, - showMode: Constants.MODE_SHOW_ONLY_WEEK); + showMode: CalendarConstants.MODE_SHOW_ONLY_WEEK); controller.addMonthChangeListener( (year, month) { diff --git a/example/lib/progress_style_page.dart b/example/lib/progress_style_page.dart index 39a5cf3..a36bd80 100644 --- a/example/lib/progress_style_page.dart +++ b/example/lib/progress_style_page.dart @@ -41,13 +41,8 @@ class _ProgressStylePageState extends State { }; controller = new CalendarController( - extraDataMap: progressMap, - weekBarItemWidgetBuilder: () { - return CustomStyleWeekBarItem(); - }, - dayWidgetBuilder: (dateModel) { - return ProgressStyleDayWidget(dateModel); - }); + extraDataMap: progressMap, + ); controller.addMonthChangeListener( (year, month) { @@ -97,8 +92,13 @@ class _ProgressStylePageState extends State { ], ), CalendarViewWidget( - calendarController: controller, - ), + calendarController: controller, + weekBarItemWidgetBuilder: () { + return CustomStyleWeekBarItem(); + }, + dayWidgetBuilder: (dateModel) { + return ProgressStyleDayWidget(dateModel); + }), ValueListenableBuilder( valueListenable: selectText, builder: (context, value, child) { diff --git a/example/lib/red_style_page.dart b/example/lib/red_style_page.dart new file mode 100644 index 0000000..a9f4501 --- /dev/null +++ b/example/lib/red_style_page.dart @@ -0,0 +1,236 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_custom_calendar/flutter_custom_calendar.dart'; + +class RedStylePage extends StatefulWidget { + RedStylePage({Key key, this.title}) : super(key: key); + + final String title; + + @override + _RedStylePageState createState() => _RedStylePageState(); +} + +class _RedStylePageState extends State { + ValueNotifier text; + ValueNotifier selectText; + + CalendarController controller; + + Map customExtraData = {}; + + Color pinkColor = Color(0xffFF8291); + + @override + void initState() { + controller = new CalendarController( + showMode: CalendarConstants.MODE_SHOW_MONTH_AND_WEEK, + extraDataMap: customExtraData); + + 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) { + var calendarWidget = CalendarViewWidget( + calendarController: controller, + margin: EdgeInsets.only(top: 20), + weekBarItemWidgetBuilder: () { + return CustomStyleWeekBarItem(); + }, + dayWidgetBuilder: (dateModel) { + return CustomStyleDayWidget(dateModel); + }, + ); + + return SafeArea( + child: Scaffold( + appBar: AppBar(), + body: new Container( + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 20), + child: new Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + SizedBox( + height: 20, + ), + Stack( + alignment: Alignment.center, + children: [ + ValueListenableBuilder( + valueListenable: text, + builder: (context, value, child) { + return new Text( + "${text.value}", + style: TextStyle( + fontSize: 20, + color: Colors.black, + fontWeight: FontWeight.w700), + ); + }), + Positioned( + left: 0, + child: Icon( + Icons.notifications, + color: pinkColor, + ), + ), + Positioned( + right: 40, + child: Icon( + Icons.search, + color: pinkColor, + ), + ), + Positioned( + right: 0, + child: Icon( + Icons.add, + color: pinkColor, + ), + ), + ], + ), + calendarWidget, + ValueListenableBuilder( + valueListenable: selectText, + builder: (context, value, child) { + return Padding( + padding: const EdgeInsets.all(20.0), + child: 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. + ), + ); + } +} + +class CustomStyleWeekBarItem extends BaseWeekBar { + List weekList = ["M", "T", "W", "T", "F", "S", "S"]; + + //可以直接重写build方法 + @override + Widget build(BuildContext context) { + List children = List(); + + var items = getWeekDayWidget(); + children.add(Row( + children: items, + )); + children.add(Divider( + color: Colors.grey, + )); + return Column( + children: children, + ); + } + + @override + Widget getWeekBarItem(int index) { + return new Container( + margin: EdgeInsets.only(top: 10, bottom: 10), + child: new Center( + child: new Text( + weekList[index], + style: + TextStyle(fontWeight: FontWeight.w700, color: Color(0xffBBC0C6)), + ), + ), + ); + } +} + +class CustomStyleDayWidget extends BaseCombineDayWidget { + CustomStyleDayWidget(DateModel dateModel) : super(dateModel); + + TextStyle normalTextStyle = + TextStyle(fontWeight: FontWeight.w700, color: Colors.black); + + TextStyle noIsCurrentMonthTextStyle = + TextStyle(fontWeight: FontWeight.w700, color: Colors.grey); + + @override + Widget getNormalWidget(DateModel dateModel) { + return Container( + margin: EdgeInsets.all(8), + child: new Stack( + alignment: Alignment.center, + children: [ + new Column( + mainAxisSize: MainAxisSize.max, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + //公历 + new Expanded( + child: Center( + child: new Text( + dateModel.day.toString(), + style: dateModel.isCurrentMonth + ? normalTextStyle + : noIsCurrentMonthTextStyle, + ), + ), + ), + ], + ), + ], + ), + ); + } + + @override + Widget getSelectedWidget(DateModel dateModel) { + return Container( +// margin: EdgeInsets.all(8), + decoration: new BoxDecoration( + shape: BoxShape.circle, + color: Color(0xffFF8291), + ), + child: new Stack( + alignment: Alignment.center, + children: [ + new Column( + mainAxisSize: MainAxisSize.max, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + //公历 + new Expanded( + child: Center( + child: new Text( + dateModel.day.toString(), + style: TextStyle(color: Colors.white), + ), + ), + ), + ], + ), + ], + ), + ); + } +} diff --git a/lib/calendar_provider.dart b/lib/calendar_provider.dart index 846e4a1..a4db0c1 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/cache_data.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/LogUtil.dart'; import 'package:flutter_custom_calendar/utils/date_util.dart'; @@ -110,6 +111,10 @@ class CalendarProvider extends ChangeNotifier { CalendarConfiguration calendarConfiguration, EdgeInsetsGeometry padding, EdgeInsetsGeometry margin, + double itemSize, + double verticalSpacing, + DayWidgetBuilder dayWidgetBuilder, + WeekBarItemWidgetBuilder weekBarItemWidgetBuilder, }) { LogUtil.log(TAG: this.runtimeType, message: "CalendarProvider initData"); if (selectedDateList != null) { @@ -119,14 +124,21 @@ class CalendarProvider extends ChangeNotifier { this.calendarConfiguration = calendarConfiguration; this.calendarConfiguration.padding = padding; this.calendarConfiguration.margin = margin; + this.calendarConfiguration.itemSize = itemSize; + this.calendarConfiguration.verticalSpacing = verticalSpacing; + this.calendarConfiguration.dayWidgetBuilder=dayWidgetBuilder; + this.calendarConfiguration.weekBarItemWidgetBuilder=weekBarItemWidgetBuilder; + //lastClickDateModel,默认是选中的item,如果为空的话,默认是当前的时间 this.lastClickDateModel = selectDateModel != null ? selectDateModel : DateModel.fromDateTime(DateTime.now()) ..day = 15; //初始化展示状态 - if (calendarConfiguration.showMode == Constants.MODE_SHOW_ONLY_WEEK || - calendarConfiguration.showMode == Constants.MODE_SHOW_WEEK_AND_MONTH) { + if (calendarConfiguration.showMode == + CalendarConstants.MODE_SHOW_ONLY_WEEK || + calendarConfiguration.showMode == + CalendarConstants.MODE_SHOW_WEEK_AND_MONTH) { expandStatus = ValueNotifier(false); } else { expandStatus = ValueNotifier(true); @@ -151,8 +163,10 @@ class CalendarProvider extends ChangeNotifier { } //如果第一个页面展示的是月视图,需要计算下初始化的高度 - if (calendarConfiguration.showMode == Constants.MODE_SHOW_ONLY_MONTH || - calendarConfiguration.showMode == Constants.MODE_SHOW_MONTH_AND_WEEK) { + if (calendarConfiguration.showMode == + CalendarConstants.MODE_SHOW_ONLY_MONTH || + calendarConfiguration.showMode == + CalendarConstants.MODE_SHOW_MONTH_AND_WEEK) { int lineCount = DateUtil.getMonthViewLineCount( calendarConfiguration.nowYear, calendarConfiguration.nowMonth); totalHeight = calendarConfiguration.itemSize * (lineCount) + diff --git a/lib/configuration.dart b/lib/configuration.dart index 798c3cd..2047d50 100644 --- a/lib/configuration.dart +++ b/lib/configuration.dart @@ -41,9 +41,9 @@ class CalendarConfiguration { /** * UI绘制方面的绘制 */ + double itemSize; //默认是屏幕宽度/7 double verticalSpacing; //日历item之间的竖直方向间距,默认10 BoxDecoration boxDecoration; //整体的背景设置 - double itemSize; //默认是屏幕宽度/7 EdgeInsetsGeometry padding; EdgeInsetsGeometry margin; diff --git a/lib/constants/constants.dart b/lib/constants/constants.dart index c87b3ac..2917567 100644 --- a/lib/constants/constants.dart +++ b/lib/constants/constants.dart @@ -1,4 +1,4 @@ -class Constants { +class CalendarConstants { //单选或者多选模式 static const int MODE_SINGLE_SELECT = 1; diff --git a/lib/controller.dart b/lib/controller.dart index d131673..c52c276 100644 --- a/lib/controller.dart +++ b/lib/controller.dart @@ -31,10 +31,8 @@ class CalendarController { PageController weekController; //星期的controller CalendarController( - {int selectMode = Constants.MODE_SINGLE_SELECT, - int showMode = Constants.MODE_SHOW_ONLY_MONTH, - DayWidgetBuilder dayWidgetBuilder = defaultCustomDayWidget, - WeekBarItemWidgetBuilder weekBarItemWidgetBuilder = defaultWeekBarWidget, + {int selectMode = CalendarConstants.MODE_SINGLE_SELECT, + int showMode = CalendarConstants.MODE_SHOW_ONLY_MONTH, int minYear = 1971, int maxYear = 2055, int minYearMonth = 1, @@ -50,8 +48,6 @@ class CalendarController { Set selectedDateTimeList = EMPTY_SET, DateModel selectDateModel, int maxMultiSelectCount = 9999, - double verticalSpacing = 10, - double itemSize, Map extraDataMap = EMPTY_MAP}) { LogUtil.log(TAG: this.runtimeType, message: "init CalendarConfiguration"); //如果没有指定当前月份和年份,默认是当年时间 @@ -62,26 +58,22 @@ class CalendarController { nowMonth = DateTime.now().month; } calendarConfiguration = CalendarConfiguration( - selectMode: selectMode, - showMode: showMode, - minYear: minYear, - maxYear: maxYear, - maxYearMonth: maxYearMonth, - nowYear: nowYear, - nowMonth: nowMonth, - minSelectYear: minSelectYear, - minSelectMonth: minSelectMonth, - minYearMonth: minYearMonth, - minSelectDay: minSelectDay, - maxSelectYear: maxSelectYear, - maxSelectMonth: maxSelectMonth, - extraDataMap: extraDataMap, - maxSelectDay: maxSelectDay, - verticalSpacing: verticalSpacing, - itemSize: itemSize); - - calendarConfiguration.dayWidgetBuilder = dayWidgetBuilder; - calendarConfiguration.weekBarItemWidgetBuilder = weekBarItemWidgetBuilder; + selectMode: selectMode, + showMode: showMode, + minYear: minYear, + maxYear: maxYear, + maxYearMonth: maxYearMonth, + nowYear: nowYear, + nowMonth: nowMonth, + minSelectYear: minSelectYear, + minSelectMonth: minSelectMonth, + minYearMonth: minYearMonth, + minSelectDay: minSelectDay, + maxSelectYear: maxSelectYear, + maxSelectMonth: maxSelectMonth, + extraDataMap: extraDataMap, + maxSelectDay: maxSelectDay, + ); if (selectedDateTimeList != null && selectedDateTimeList.isNotEmpty) { calendarConfiguration.defaultSelectedDateList @@ -100,7 +92,7 @@ class CalendarController { maxYearMonth, ))}"); - if (showMode != Constants.MODE_SHOW_ONLY_WEEK) { + if (showMode != CalendarConstants.MODE_SHOW_ONLY_WEEK) { //初始化pageController,initialPage默认是当前时间对于的页面 int initialPage = 0; int nowMonthIndex = 0; @@ -138,7 +130,7 @@ class CalendarController { "初始化月份视图的信息:一共有${monthList.length}个月,initialPage为${nowMonthIndex}"); } - if (showMode != Constants.MODE_SHOW_ONLY_MONTH) { + if (showMode != CalendarConstants.MODE_SHOW_ONLY_MONTH) { //计算一共多少周 //计算方法:第一天是周几,最后一天是周几,中间的天数/7后加上2就是结果了 int initialWeekPage = 0; @@ -182,8 +174,6 @@ class CalendarController { calendarConfiguration.weekList = weekList; calendarConfiguration.monthController = monthController; calendarConfiguration.weekController = weekController; - calendarConfiguration.dayWidgetBuilder = dayWidgetBuilder; - calendarConfiguration.weekBarItemWidgetBuilder = weekBarItemWidgetBuilder; } //月份切换监听 diff --git a/lib/utils/lunar_util.dart b/lib/utils/lunar_util.dart index 23b0755..ce18e9a 100644 --- a/lib/utils/lunar_util.dart +++ b/lib/utils/lunar_util.dart @@ -908,7 +908,7 @@ class LunarUtil { if (day == 1) { return numToChineseMonth(month, leap); } - return Constants.LUNAR_DAY_TEXT[day - 1]; + return CalendarConstants.LUNAR_DAY_TEXT[day - 1]; } /** @@ -920,9 +920,9 @@ class LunarUtil { */ static String numToChineseMonth(int month, int leap) { if (leap == 1) { - return "闰" + Constants.LUNAR_MONTH_TEXT[month - 1]; + return "闰" + CalendarConstants.LUNAR_MONTH_TEXT[month - 1]; } - return Constants.LUNAR_MONTH_TEXT[month - 1]; + return CalendarConstants.LUNAR_MONTH_TEXT[month - 1]; } static String getString(int month, int day) { diff --git a/lib/widget/calendar_view.dart b/lib/widget/calendar_view.dart index f5d6c7b..d8b1871 100644 --- a/lib/widget/calendar_view.dart +++ b/lib/widget/calendar_view.dart @@ -3,7 +3,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_custom_calendar/calendar_provider.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/LogUtil.dart'; import 'package:flutter_custom_calendar/utils/date_util.dart'; import 'package:flutter_custom_calendar/widget/month_view_pager.dart'; @@ -23,15 +22,28 @@ class CalendarViewWidget extends StatefulWidget { EdgeInsetsGeometry padding; EdgeInsetsGeometry margin; + //默认是屏幕宽度/7 + double itemSize; + + //日历item之间的竖直方向间距,默认10 + double verticalSpacing; + + DayWidgetBuilder dayWidgetBuilder; + WeekBarItemWidgetBuilder weekBarItemWidgetBuilder; + //控制器 final CalendarController calendarController; CalendarViewWidget( {Key key, + this.dayWidgetBuilder = defaultCustomDayWidget, + this.weekBarItemWidgetBuilder = defaultWeekBarWidget, @required this.calendarController, this.boxDecoration, this.padding = EdgeInsets.zero, - this.margin = EdgeInsets.zero}) + this.margin = EdgeInsets.zero, + this.verticalSpacing = 10, + this.itemSize}) : super(key: key); @override @@ -45,7 +57,11 @@ class _CalendarViewWidgetState extends State { widget.calendarController.calendarProvider.initData( calendarConfiguration: widget.calendarController.calendarConfiguration, padding: widget.padding, - margin: widget.margin); + margin: widget.margin, + itemSize: widget.itemSize, + verticalSpacing: widget.verticalSpacing, + dayWidgetBuilder: widget.dayWidgetBuilder, + weekBarItemWidgetBuilder: widget.weekBarItemWidgetBuilder); super.initState(); } @@ -99,15 +115,15 @@ class CalendarContainerState extends State expand = calendarProvider.expandStatus.value; if (calendarProvider.calendarConfiguration.showMode == - Constants.MODE_SHOW_ONLY_WEEK) { + CalendarConstants.MODE_SHOW_ONLY_WEEK) { widgets.add(const WeekViewPager()); } else if (calendarProvider.calendarConfiguration.showMode == - Constants.MODE_SHOW_WEEK_AND_MONTH) { + CalendarConstants.MODE_SHOW_WEEK_AND_MONTH) { widgets.add(const MonthViewPager()); widgets.add(const WeekViewPager()); index = 1; } else if (calendarProvider.calendarConfiguration.showMode == - Constants.MODE_SHOW_MONTH_AND_WEEK) { + CalendarConstants.MODE_SHOW_MONTH_AND_WEEK) { widgets.add(const MonthViewPager()); widgets.add(const WeekViewPager()); index = 0; @@ -119,9 +135,9 @@ class CalendarContainerState extends State //如果需要视图切换的话,才需要添加监听,不然不需要监听变化 if (calendarProvider.calendarConfiguration.showMode == - Constants.MODE_SHOW_WEEK_AND_MONTH || + CalendarConstants.MODE_SHOW_WEEK_AND_MONTH || calendarProvider.calendarConfiguration.showMode == - Constants.MODE_SHOW_MONTH_AND_WEEK) { + CalendarConstants.MODE_SHOW_MONTH_AND_WEEK) { calendarProvider.expandStatus.addListener(() { setState(() { print( @@ -147,7 +163,7 @@ class CalendarContainerState extends State widget.calendarController.addMonthChangeListener((year, month) { if (widget.calendarController.calendarProvider.calendarConfiguration .showMode != - Constants.MODE_SHOW_ONLY_WEEK) { + CalendarConstants.MODE_SHOW_ONLY_WEEK) { //月份切换的时候,如果高度发生变化的话,需要setState使高度整体自适应 int lineCount = DateUtil.getMonthViewLineCount(year, month); double newHeight = itemHeight * (lineCount) + diff --git a/lib/widget/default_week_bar.dart b/lib/widget/default_week_bar.dart index 1961586..0b8935e 100644 --- a/lib/widget/default_week_bar.dart +++ b/lib/widget/default_week_bar.dart @@ -47,7 +47,7 @@ class DefaultWeekBar extends BaseWeekBar { height: 40, alignment: Alignment.center, child: new Text( - Constants.WEEK_LIST[index], + CalendarConstants.WEEK_LIST[index], style: topWeekTextStyle, ), ); diff --git a/lib/widget/month_view.dart b/lib/widget/month_view.dart index 6b3a8d5..9c02b49 100644 --- a/lib/widget/month_view.dart +++ b/lib/widget/month_view.dart @@ -125,7 +125,7 @@ class _MonthViewState extends State itemBuilder: (context, index) { DateModel dateModel = items[index]; //判断是否被选择 - if (configuration.selectMode == Constants.MODE_MULTI_SELECT) { + if (configuration.selectMode == CalendarConstants.MODE_MULTI_SELECT) { if (calendarProvider.selectedDateList.contains(dateModel)) { dateModel.isSelected = true; } else { @@ -213,7 +213,7 @@ class ItemContainerState extends State { //范围外不可点击 if (!dateModel.isInRange) { //多选回调 - if (configuration.selectMode == Constants.MODE_MULTI_SELECT) { + if (configuration.selectMode == CalendarConstants.MODE_MULTI_SELECT) { configuration.multiSelectOutOfRange(); } return; @@ -221,7 +221,7 @@ class ItemContainerState extends State { calendarProvider.lastClickDateModel = dateModel; - if (configuration.selectMode == Constants.MODE_MULTI_SELECT) { + if (configuration.selectMode == CalendarConstants.MODE_MULTI_SELECT) { //多选,判断是否超过限制,超过范围 if (calendarProvider.selectedDateList.length == configuration.maxMultiSelectCount) { diff --git a/lib/widget/week_view.dart b/lib/widget/week_view.dart index c71bb6f..7542ffc 100644 --- a/lib/widget/week_view.dart +++ b/lib/widget/week_view.dart @@ -72,7 +72,7 @@ class _WeekViewState extends State { itemBuilder: (context, index) { DateModel dateModel = items[index]; //判断是否被选择 - if (configuration.selectMode == Constants.MODE_MULTI_SELECT) { + if (configuration.selectMode == CalendarConstants.MODE_MULTI_SELECT) { if (calendarProvider.selectedDateList.contains(dateModel)) { dateModel.isSelected = true; } else {