The effect

The prototype

The development of

  1. use
          // The attendance calendar
            DatePickerDialog(
              initialDate: DateTime.now(),
              firstDate: DateTime(2020),
              lastDate: DateTime(2030),
              onDateChanged: onDateChanged,
              // 0: no status, 1: normal attendance 2: abnormal status, late, early leave,
              // If there is less than a month, the calendar automatically fills up the month with 0
              checking: [
                0.0.1.2,,),Copy the code

DatePickerDialog exists in the material package of a Flutter. The calendar of a Flutter exists in the form of a dialog. In this paper, the dialog is changed into a StatefulWidget directly in the page to remove unnecessary things. Make the changes directly on _DayPicker in material/calendar_date_picker.dart. 2. Modify the date style in the calendar:

 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(() (() [() [() [() [()Copy the code

The blue dot will be displayed below the date display if the time limit is normal, and the orange dot will be displayed if the time limit is abnormal. If the date limit is not undefined, the checking will be passed in using DatePickerDialog. Since the calendar starts from 1, the checking will be performed by using DatePickerDialog. The array starts with index 0, so checking[day-1] is the exact checking status for a particular day. Day is all the dates in a month.

2. Set the title of the week after modification:

  List<Widget> _dayHeaders(a) {
    final List<Widget> result = <Widget>[];
    final List<String> weekdays = ["Day"."一"."二"."Three"."Four"."Five"."Six"];
    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;
  }
Copy the code

The original:

  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;
  }
Copy the code

Localizations. FirstDayOfWeekIndex returns a value of 0 or 1, if return 0, for the first day of the week is Sunday; If 1 is returned, Monday is the first day of the week. This article is not from the localizations. FirstDayOfWeekIndex access, direct assignment of 1, every week from Monday.

3. Complete the blank date of each month:

  • Gets the number of days in the specified month
  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];
  }
Copy the code
  • Specified in 1, the offset, the first day of the week, every month if no. 1 is week 3, because the calendar from the first day of a week, so the first Monday of the week in a week, on Tuesday as blank, need two days after the completion the reciprocal of last month, so you also need to get two days last month, which is the last two days.
// Get the date offset
  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; }...// Start date of completion
     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 Number of days in the last month - if the date of the current month is offset, the date missing from the beginning of the current month can be filled in
              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{... }... }}Copy the code
  • If the last day of each month falls on a Sunday, there is no need to complete the calendar. If the last day of each month falls on a Friday, the first two days of the next month are filled on Saturday and Sunday of the current month:
    if ((daysInMonth + dayOffset) % 7 > 0) {
    // Calculate how many days you need to make up, starting at 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(() (() [() (() [() (() [() }}Copy the code
  1. Calculate how many lines can be displayed from Monday in each month, that is, calculate the height of the calendar. The height is different according to the month, at least 4 lines, at most 6 lines, according to the content of the dynamic display will not leave a lot of blank
    // Calculate the number of days in a month
    int daysInMonth = ChinaDateUtils.getDaysInMonth(
        widget.initialDate.year, widget.initialDate.month);
     // Calculate the week of the first day of each month
    int dayOffset = ChinaDateUtils.firstDayOffsets(
        widget.initialDate.year, widget.initialDate.month);
    // Calculate how many lines to display all dates
    int row = ((daysInMonth + dayOffset) / 7).ceil();
Copy the code

You can probably do this by modifying these things. Demo address: gitee.com/masshub/sig…