Flutter仿钉钉考勤日历 Flutter仿钉钉考勤日历的代码实例
阿品 人气:1本文主要介绍了Flutter仿钉钉考勤日历的示例代码,分享给大家,具体如下:
效果
原型
开发
1. 使用
// 考勤日历 DatePickerDialog( initialDate: DateTime.now(), firstDate: DateTime(2020), lastDate: DateTime(2030), onDateChanged: onDateChanged, // 0:无状态,1:正常考勤 2:异常考情,迟到,早退, // 若不满一个月,日历会自动用0补满一个月 checking: [ 0, 0, 1, 2, ], ),
DatePickerDialog是在存在与Flutter的material包中,Flutter自带的日历是以dialog形式存在的,本文将dialog改成StatefulWidget直接在页面中,将多余东西去掉,直接在material/calendar_date_picker.dart中_DayPicker上进行修改。
2. 修改日历中日期样式:
Widget dayWidget = Container( margin: EdgeInsets.all(4.0), decoration: decoration, alignment: Alignment.center, child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text(localizations.formatDecimal(day), style: TextStyle( fontSize: 14.0, color: dayColor, fontWeight: FontWeight.bold)), Visibility( visible: checking[day - 1] == 1 || checking[day - 1] == 2, child: Container( height: 6.0, width: 6.0, decoration: BoxDecoration( shape: BoxShape.circle, color: isSelectedDay ? Colors.white : (checking[day - 1] == 1 ? Color(0xFF1376EE): Color(0xFFFF8A21)), ), ), ), ], ), );
Visibility原来没有,是修改加上去的,主要是显示当天打卡状态,若打卡正常则在日期显示下方显示蓝色小点,若有异常则显示橙色的点,若没有状态就不显示,checking则是使用DatePickerDialog传入的,由于日历从1开始,数组是从索引0开始的,所以使用checking[day - 1]才能准确获取某一日的打卡状态,day 则是日历中某一月中所有日期。
3.设置星期标题
修改后:
List<Widget> _dayHeaders() { final List<Widget> result = <Widget>[]; final List<String> weekdays = ["日", "一", "二", "三", "四", "五", "六"]; for (int i = 1; true; i = (i + 1) % 7) { final String weekday = weekdays[i]; result.add(ExcludeSemantics( child: Center( child: Text(weekday, style: TextStyle(fontSize: 14.0, color: Color(0xFF999999)))), )); if (i == (1 - 1) % 7) break; } return result; }
原文:
List<Widget> _dayHeaders(TextStyle? headerStyle, MaterialLocalizations localizations) { final List<Widget> result = <Widget>[]; for (int i = localizations.firstDayOfWeekIndex; true; i = (i + 1) % 7) { final String weekday = localizations.narrowWeekdays[i]; result.add(ExcludeSemantics( child: Center(child: Text(weekday, style: headerStyle)), )); if (i == (localizations.firstDayOfWeekIndex - 1) % 7) break; } return result; }
localizations.firstDayOfWeekIndex返回值为0或者1,若返回0,则星期日为每周的第一天;若返回1,则星期一为每周的第一天。本文中没有从localizations.firstDayOfWeekIndex获取,直接赋值为1,则每周从星期一开始。
4.补全每个月空白日期:
获取指定月份有多少天
static int getDaysInMonth(int year, int month) { if(month < 1){ year = year - 1; month = month + 12; } if(month > 12){ year = year + 1; month = month - 12; } if (month == DateTime.february) { final bool isLeapYear = (year % 4 == 0) && (year % 100 != 0) || (year % 400 == 0); return isLeapYear ? 29 : 28; } const List<int> daysInMonth = <int>[31, -1, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; return daysInMonth[month - 1]; }
获取指定月份1日的偏移量,即每个月第一天是星期几,若1号是星期3,因为日历每周是从第一天开始的,所以第一周的星期的星期一,星期二为空白,需要补全上个月的倒数后两天,所以还需要获取上个月的最后两天是哪两天。
// 获取日期偏移 static int firstDayOffsets(int year, int month) { final int weekdayFromMonday = DateTime(year, month).weekday - 1; int firstDayOfWeekIndex = 1; firstDayOfWeekIndex = (firstDayOfWeekIndex - 1) % 7; return (weekdayFromMonday - firstDayOfWeekIndex) % 7; } ... // 补全开始日期 int day = -dayOffset; while (day < daysInMonth) { day++; if (day < 1) { dayItems.add(Container( margin: EdgeInsets.all(4.0), alignment: Alignment.center, child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ // daysInPreMonth上个月的天数-本月日期偏移则可把本月开始缺失的日期补全 Text(localizations.formatDecimal(daysInPreMonth - day.abs()), style: TextStyle( fontSize: 14.0, color: Color(0xFF888888), fontWeight: FontWeight.bold)), Visibility( visible: false, child: Container( height: 6.0, width: 6.0, decoration: BoxDecoration( shape: BoxShape.circle, color: Color(0xFFFF8A21), ), ), ), ], ), )); } else { ... } ... } }
补全日历结束日期,每个月最后一天若为星期日,则无需补全,若为星期五则把下个月的前两天补在本月的星期六和星期日:
if ((daysInMonth + dayOffset) % 7 > 0) { // 计算需要补多少天,直接从1开始就好 int addNum = 7 - ((daysInMonth + dayOffset) % 7); for (int i = 1; i <= addNum; i++) { dayItems.add(Container( margin: EdgeInsets.all(4.0), alignment: Alignment.center, child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text(localizations.formatDecimal(i), style: TextStyle( fontSize: 14.0, color: Color(0xFF888888), fontWeight: FontWeight.bold)), Visibility( visible: false, child: Container( height: 6.0, width: 6.0, decoration: BoxDecoration( shape: BoxShape.circle, color: Color(0xFFFF8A21), ), ), ), ], ), )); } }
计算每个月从星期一开始展示可以展示几行,即计算日历高度,月份不同,高度不同,最少4行,最多6行,根据内容动态显示不至于留大量空白
// 计算一个月有多少天 int daysInMonth = ChinaDateUtils.getDaysInMonth( widget.initialDate.year, widget.initialDate.month); // 计算每个月第一天的星期 int dayOffset = ChinaDateUtils.firstDayOffsets( widget.initialDate.year, widget.initialDate.month); // 计算用多少行展示所有日期 int row = ((daysInMonth + dayOffset) / 7).ceil();
修改这些内容大概可以实现上述效果。
加载全部内容