|
@@ -1,9 +1,11 @@
|
|
|
import 'dart:html';
|
|
|
|
|
|
-import 'package:calendar_view/calendar_view/calendar_util.dart';
|
|
|
+import 'package:calendar_view/calendar_controller/controller.dart';
|
|
|
+import 'package:calendar_view/utils/calendar_util.dart';
|
|
|
import 'package:calendar_view/calendar_view/month_calendar/month_calendar_item.dart';
|
|
|
import 'package:flutter/foundation.dart';
|
|
|
import 'package:flutter/material.dart';
|
|
|
+import 'package:get/get.dart';
|
|
|
|
|
|
class MonthCalendar extends StatefulWidget {
|
|
|
const MonthCalendar({super.key});
|
|
@@ -13,49 +15,15 @@ class MonthCalendar extends StatefulWidget {
|
|
|
}
|
|
|
|
|
|
class _MonthCalendarState extends State<MonthCalendar> {
|
|
|
- int currentYear = 2022; // 当前年份
|
|
|
- int currentMonth = 12; // 当前月份
|
|
|
- int selectedDayIndex = 0; // 当前选择的日期的下标,从0开始,范围是0-34 有时是 0-41
|
|
|
- int maxDaysLength = 35; // 最大的日期数组长度,有时是42
|
|
|
- List<DayStructure> daysList = []; // 当前维护的日期列表
|
|
|
+ List<DayStructure> daysList = []; // 当前控制器的日期列表
|
|
|
+ CalendarController calendarController = Get.find<CalendarController>();
|
|
|
int _maxScheduleLines = 3; // 最大的日程行数【需要动态计算】
|
|
|
double _viewHeight = 0; // 维护一个视口高度,如果视口高度不变,那么日程的高度不需要计算
|
|
|
-
|
|
|
+ int _calendarLines = 0; // 维护一个日历行数,如果日历行数不变,那么日程的高度不需要计算
|
|
|
@override
|
|
|
void initState() {
|
|
|
super.initState();
|
|
|
|
|
|
- /// 获取当前时间判断年月
|
|
|
- final DateTime now = DateTime.now();
|
|
|
- currentYear = now.year;
|
|
|
- currentMonth = now.month;
|
|
|
- daysList = _countDaysList(currentYear, currentMonth);
|
|
|
- _selectToday();
|
|
|
-
|
|
|
- /// 虚拟的日程数据
|
|
|
- final List<DateTime> mockSchedule = [
|
|
|
- DateTime(2022, 12, 1),
|
|
|
- DateTime(2022, 12, 4),
|
|
|
- DateTime(2022, 12, 5),
|
|
|
- DateTime(2022, 12, 6),
|
|
|
- DateTime(2022, 12, 7),
|
|
|
- DateTime(2022, 12, 12),
|
|
|
- DateTime(2022, 12, 13),
|
|
|
- DateTime(2022, 12, 14),
|
|
|
- DateTime(2022, 12, 15),
|
|
|
- DateTime(2022, 12, 16),
|
|
|
- DateTime(2022, 12, 17),
|
|
|
- DateTime(2022, 12, 18),
|
|
|
- DateTime(2022, 12, 19),
|
|
|
- DateTime(2022, 12, 20),
|
|
|
- DateTime(2022, 12, 27),
|
|
|
- DateTime(2022, 12, 28),
|
|
|
- DateTime(2022, 12, 29),
|
|
|
- DateTime(2022, 12, 30),
|
|
|
- DateTime(2022, 12, 31),
|
|
|
- ];
|
|
|
- _setSchedule(mockSchedule);
|
|
|
-
|
|
|
/// 监控resize事件,动态计算最大日程行数
|
|
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
|
|
_handleMaxScheduleLines();
|
|
@@ -69,6 +37,21 @@ class _MonthCalendarState extends State<MonthCalendar> {
|
|
|
});
|
|
|
});
|
|
|
}
|
|
|
+ daysList = calendarController.daysList;
|
|
|
+ calendarController.onDaysListChange.addListener(_onDaysListChange);
|
|
|
+ }
|
|
|
+
|
|
|
+ @override
|
|
|
+ void dispose() {
|
|
|
+ super.dispose();
|
|
|
+ calendarController.onDaysListChange.removeListener(_onDaysListChange);
|
|
|
+ }
|
|
|
+
|
|
|
+ void _onDaysListChange(_, e) {
|
|
|
+ setState(() {
|
|
|
+ daysList = calendarController.daysList;
|
|
|
+ });
|
|
|
+ _handleMaxScheduleLines();
|
|
|
}
|
|
|
|
|
|
@override
|
|
@@ -159,162 +142,21 @@ class _MonthCalendarState extends State<MonthCalendar> {
|
|
|
),
|
|
|
child: MonthDayItem(
|
|
|
dayData: day,
|
|
|
- onSelect: (v) => _handleSelectedDayByIndex(v),
|
|
|
maxScheduleLines: _maxScheduleLines,
|
|
|
),
|
|
|
),
|
|
|
);
|
|
|
}
|
|
|
|
|
|
- /// 传入起始年月,返回35个日期结构体
|
|
|
- List<DayStructure> _countDaysList(int year, int month) {
|
|
|
- maxDaysLength = _isNeedExtraRow(year, month) ? 42 : 35;
|
|
|
- final daysList = <DayStructure>[];
|
|
|
- final firstDay = DateTime(year, month, 1);
|
|
|
- final firstDayWeek = firstDay.weekday;
|
|
|
- final lastDay = DateTime(year, month + 1, 0);
|
|
|
- final lastDayOfMonth = lastDay.day;
|
|
|
- final lastDayOfLastMonth = DateTime(year, month, 0).day;
|
|
|
- final today = DateTime.now();
|
|
|
-
|
|
|
- /// 转换后的 firstDayWeek
|
|
|
- final firstDayWeekIndex = (firstDayWeek) % 7;
|
|
|
- int nextMonthDay = 1;
|
|
|
-
|
|
|
- // 上个月的日期
|
|
|
- for (var i = 0; i < firstDayWeekIndex; i++) {
|
|
|
- daysList.add(
|
|
|
- DayStructure(
|
|
|
- index: i,
|
|
|
- date: DateTime(
|
|
|
- year, month - 1, lastDayOfLastMonth - firstDayWeekIndex + i + 1),
|
|
|
- isCurrentMonth: false,
|
|
|
- ),
|
|
|
- );
|
|
|
- }
|
|
|
-
|
|
|
- // 当月的日期
|
|
|
- for (var i = 0;
|
|
|
- (i < lastDayOfMonth) && daysList.length < maxDaysLength;
|
|
|
- i++) {
|
|
|
- daysList.add(
|
|
|
- DayStructure(
|
|
|
- index: i + firstDayWeek,
|
|
|
- date: DateTime(year, month, i + 1),
|
|
|
- isToday:
|
|
|
- today.year == year && today.month == month && today.day == i + 1,
|
|
|
- ),
|
|
|
- );
|
|
|
- }
|
|
|
-
|
|
|
- while (daysList.length < maxDaysLength) {
|
|
|
- daysList.add(DayStructure(
|
|
|
- index: daysList.length,
|
|
|
- date: DateTime(month == 12 ? year + 1 : year,
|
|
|
- month == 12 ? 1 : month + 1, nextMonthDay),
|
|
|
- isCurrentMonth: false,
|
|
|
- ));
|
|
|
- nextMonthDay++;
|
|
|
- }
|
|
|
- return daysList;
|
|
|
- }
|
|
|
-
|
|
|
- /// 计算是否需要显示六行日期,一般为5行,但是有时候会有6行
|
|
|
- bool _isNeedExtraRow(int year, int month) {
|
|
|
- final firstDay = DateTime(year, month, 1);
|
|
|
- final firstDayWeek = firstDay.weekday;
|
|
|
- final lastDay = DateTime(year, month + 1, 0);
|
|
|
- final lastDayOfMonth = lastDay.day;
|
|
|
-
|
|
|
- /// 转换后的firstDayWeek,%7是因为DateTime的weekday是从周日开始的,而我们的日历是从周一开始的
|
|
|
- final firstDayWeekIndex = (firstDayWeek) % 7;
|
|
|
- return firstDayWeekIndex + lastDayOfMonth > 35;
|
|
|
- }
|
|
|
-
|
|
|
- /// 通过下标选中日期,下标从0开始,允许的范围是0-34,有时是 0-42
|
|
|
- void _handleSelectedDayByIndex(int index) {
|
|
|
- assert(index >= 0 && index < maxDaysLength,
|
|
|
- 'index must be in 0-$maxDaysLength');
|
|
|
- assert(daysList.length == maxDaysLength,
|
|
|
- 'daysList length must be maxDaysLength');
|
|
|
- for (var element in daysList) {
|
|
|
- if (element.index == index) {
|
|
|
- element.isSelected = true;
|
|
|
- } else {
|
|
|
- element.isSelected = false;
|
|
|
- }
|
|
|
- }
|
|
|
- selectedDayIndex = index;
|
|
|
- setState(() {});
|
|
|
- }
|
|
|
-
|
|
|
- /// 选中当月第一天
|
|
|
- void _selectFirstDay() {
|
|
|
- for (var element in daysList) {
|
|
|
- if (element.isCurrentMonth) {
|
|
|
- _handleSelectedDayByIndex(element.index);
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /// 选中今天
|
|
|
- void _selectToday() {
|
|
|
- for (var element in daysList) {
|
|
|
- if (element.isToday) {
|
|
|
- _handleSelectedDayByIndex(element.index);
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /// 给日期设置日程的值
|
|
|
- void _setSchedule(List<DateTime> scheduleList) {
|
|
|
- /// 如果scheduleList中存在daysList中的日期,则设置hasSchedule为true
|
|
|
- for (var element in scheduleList) {
|
|
|
- for (var day in daysList) {
|
|
|
- if (element.year == day.date.year &&
|
|
|
- element.month == day.date.month &&
|
|
|
- element.day == day.date.day) {
|
|
|
- day.hasSchedule = true;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /// 上个月
|
|
|
- void _handleLastMonth() {
|
|
|
- if (currentMonth == 1) {
|
|
|
- currentMonth = 12;
|
|
|
- currentYear--;
|
|
|
- } else {
|
|
|
- currentMonth--;
|
|
|
- }
|
|
|
- daysList = _countDaysList(currentYear, currentMonth);
|
|
|
- _selectFirstDay();
|
|
|
- setState(() {});
|
|
|
- }
|
|
|
-
|
|
|
- /// 下个月
|
|
|
- void _handleNextMonth() {
|
|
|
- if (currentMonth == 12) {
|
|
|
- currentMonth = 1;
|
|
|
- currentYear++;
|
|
|
- } else {
|
|
|
- currentMonth++;
|
|
|
- }
|
|
|
- daysList = _countDaysList(currentYear, currentMonth);
|
|
|
- _selectFirstDay();
|
|
|
- setState(() {});
|
|
|
- }
|
|
|
-
|
|
|
/// 动态计算日历格内的最大日程行数
|
|
|
void _handleMaxScheduleLines() {
|
|
|
final size = MediaQuery.of(context).size;
|
|
|
- if (size.height == _viewHeight) return;
|
|
|
+ if (size.height == _viewHeight &&
|
|
|
+ calendarController.calendarLines == _calendarLines) return;
|
|
|
print('计算最大日程行数');
|
|
|
_viewHeight = size.height;
|
|
|
- final gridRows = (maxDaysLength / 7).floor();
|
|
|
+ _calendarLines = calendarController.calendarLines;
|
|
|
+ final gridRows = calendarController.calendarLines;
|
|
|
final gridHeight = size.height - 100; // 100 是日历头部的高度
|
|
|
final gridItemHeight = gridHeight / gridRows;
|
|
|
final scheduleAreaHeight = gridItemHeight - 30; // 30 是日期的高度
|