flutter 手写日历组件

先看效果

 直接上代码

calendar_popup_view.dart

import 'package:flutter/material.dart';
import 'package:intl/intl.dart';

import 'custom_calendar.dart';
import 'hotel_app_theme.dart';

class CalendarPopupView extends StatefulWidget {
  const CalendarPopupView({
    required this.initialStartDate,
    required this.initialEndDate,
    required this.onApplyClick,
    required this.onCancelClick,
    required this.state,
    this.minimumDate,
    this.maximumDate,
    this.barrierDismissible = true,
    super.key,
  });

  final DateTime? minimumDate;
  final DateTime? maximumDate;
  final bool barrierDismissible;
  final DateTime initialStartDate;
  final DateTime initialEndDate;
  final Function(DateTime, DateTime) onApplyClick;

  final Function onCancelClick;
  final Function state;
  @override
  State<CalendarPopupView> createState() => _CalendarPopupViewState();
}

class _CalendarPopupViewState extends State<CalendarPopupView>
    with TickerProviderStateMixin {
  late DateTime startDate;
  late DateTime endDate;
  late final AnimationController animationController;
  late DateTime curSelectStartData;
  late DateTime curSelectEndData;
  @override
  void initState() {
    super.initState();
    animationController = AnimationController(
        duration: const Duration(milliseconds: 400), vsync: this);
    startDate = widget.initialStartDate;
    endDate = widget.initialEndDate;
    curSelectStartData = startDate;
    curSelectEndData = endDate;
    animationController.forward();
  }

  @override
  void dispose() {
    animationController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return AnimatedBuilder(
      animation: animationController,
      builder: (BuildContext context, _) {
        return AnimatedOpacity(
          duration: const Duration(milliseconds: 100),
          opacity: animationController.value,
          child: InkWell(
            splashColor: Colors.transparent,
            focusColor: Colors.transparent,
            highlightColor: Colors.transparent,
            hoverColor: Colors.transparent,
            onTap: () {
              if (widget.barrierDismissible) {
                Navigator.pop(context);
              }
            },
            child: Container(
              decoration: BoxDecoration(
                color: HotelAppTheme.buildLightTheme().colorScheme.background,
                borderRadius: const BorderRadius.all(Radius.circular(24.0)),
                boxShadow: <BoxShadow>[
                  BoxShadow(
                      color: Colors.grey.withOpacity(0.2),
                      offset: const Offset(4, 4),
                      blurRadius: 8.0),
                ],
              ),
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                crossAxisAlignment: CrossAxisAlignment.start,
                mainAxisSize: MainAxisSize.min,
                children: <Widget>[
                  Row(
                    children: <Widget>[
                      Expanded(
                        child: Column(
                          mainAxisAlignment: MainAxisAlignment.center,
                          children: <Widget>[
                            Text(
                              'From',
                              textAlign: TextAlign.left,
                              style: grayTitle(),
                            ),
                            const SizedBox(
                              height: 4,
                            ),
                            Text(
                              DateFormat('EEE, dd MMM')
                                  .format(curSelectStartData),
                              style:
                                  curSelectStartData == widget.initialStartDate
                                      ? grayTime()
                                      : primaryTime(),
                            ),
                          ],
                        ),
                      ),
                      Container(
                        height: 74,
                        width: 1,
                        color: HotelAppTheme.buildLightTheme().dividerColor,
                      ),
                      Expanded(
                        child: Column(
                          mainAxisAlignment: MainAxisAlignment.center,
                          children: <Widget>[
                            Text(
                              'To',
                              style: grayTitle(),
                            ),
                            const SizedBox(height: 4),
                            Text(
                              DateFormat('EEE, dd MMM')
                                  .format(curSelectEndData),
                              style: curSelectEndData == widget.initialEndDate
                                  ? grayTime()
                                  : primaryTime(),
                            ),
                          ],
                        ),
                      )
                    ],
                  ),
                  const Divider(height: 1),
                  CustomCalendarView(
                      minimumDate: widget.minimumDate,
                      maximumDate: widget.maximumDate,
                      initialEndDate: widget.initialEndDate,
                      initialStartDate: widget.initialStartDate,
                      startEndDateChange:
                          (DateTime startDateData, DateTime endDateData) {
                        if (mounted) {
                          setState(() {
                            startDate = startDateData;
                            endDate = endDateData;
                            curSelectStartData = startDateData;
                            curSelectEndData = endDateData;
                          });
                          toUpdateState();
                        }
                      },
                      endDateChange: (DateTime endData) {
                        print("endDateChange");
                        setState(() {
                          endDate = endData;
                          curSelectEndData = endData;
                        });
                        toUpdateState();
                      },
                      startDateChange: (DateTime startData) {
                        print("startDateChange");
                        setState(() {
                          startDate = startData;
                          curSelectStartData = startData;
                        });
                        toUpdateState();
                      }),
                  Padding(
                    padding: const EdgeInsets.only(
                        left: 16, right: 16, bottom: 16, top: 8),
                    child: Container(
                      height: 48,
                      decoration: BoxDecoration(
                        color: HotelAppTheme.buildLightTheme().primaryColor,
                        borderRadius:
                            const BorderRadius.all(Radius.circular(24.0)),
                        boxShadow: <BoxShadow>[
                          BoxShadow(
                            color: Colors.grey.withOpacity(0.6),
                            blurRadius: 8,
                            offset: const Offset(4, 4),
                          ),
                        ],
                      ),
                      child: Material(
                        color: Colors.transparent,
                        child: InkWell(
                          borderRadius:
                              const BorderRadius.all(Radius.circular(24.0)),
                          highlightColor: Colors.transparent,
                          onTap: () {
                            try {
                              // animationController?.reverse().then((f) {

                              // });
                              widget.onApplyClick(startDate, endDate);
                              Navigator.pop(context);
                            } catch (_) {}
                          },
                          child: const Center(
                            child: Text(
                              'Apply',
                              style: TextStyle(
                                  fontWeight: FontWeight.w500,
                                  fontSize: 18,
                                  color: Colors.white),
                            ),
                          ),
                        ),
                      ),
                    ),
                  )
                ],
              ),
            ),
          ),
        );
      },
    );
  }

  toUpdateState() {
    widget.state(() {});
  }

  TextStyle grayTitle() {
    return const TextStyle(
      fontWeight: FontWeight.w100,
      fontSize: 16,
      color: Color(0xff676970),
    );
  }

  TextStyle grayTime() {
    return const TextStyle(
      fontWeight: FontWeight.bold,
      fontSize: 16,
      color: Color(0xff45474D),
    );
  }

  TextStyle primaryTime() {
    return TextStyle(
      fontWeight: FontWeight.bold,
      fontSize: 16,
      color: HotelAppTheme.buildLightTheme().primaryColorDark,
    );
  }
}

custom_calendar.dart

import 'package:app/common/util/k_date_util.dart';
import 'package:app/common/util/k_log_util.dart';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:intl/intl.dart';

import 'hotel_app_theme.dart';

class CustomCalendarView extends StatefulWidget {
  const CustomCalendarView({
    required this.initialStartDate,
    required this.initialEndDate,
    required this.startEndDateChange,
    required this.startDateChange,
    required this.endDateChange,
    this.minimumDate,
    this.maximumDate,
    super.key,
  });

  final DateTime? minimumDate;
  final DateTime? maximumDate;
  final DateTime initialStartDate;
  final DateTime initialEndDate;

  final Function(DateTime, DateTime) startEndDateChange;
  final Function(DateTime) startDateChange;
  final Function(DateTime) endDateChange;
  @override
  State<CustomCalendarView> createState() => _CustomCalendarViewState();
}

class _CustomCalendarViewState extends State<CustomCalendarView> {
  List<DateTime> dateList = <DateTime>[];
  DateTime currentMonthDate = DateTime.now();
  DateTime? startDate;
  DateTime? endDate;

  @override
  void initState() {
    super.initState();
    setListOfDate(currentMonthDate);
    startDate = widget.initialStartDate;
    endDate = widget.initialEndDate;
  }

  @override
  void dispose() {
    super.dispose();
  }

  void setListOfDate(DateTime monthDate) {
    dateList.clear();
    final DateTime newDate = DateTime(monthDate.year, monthDate.month, 0);
    int previousMothDay = 0;
    if (newDate.weekday < 7) {
      previousMothDay = newDate.weekday;
      for (int i = 1; i <= previousMothDay; i++) {
        dateList.add(newDate.subtract(Duration(days: previousMothDay - i)));
      }
    }
    for (int i = 0; i < (42 - previousMothDay); i++) {
      dateList.add(newDate.add(Duration(days: i + 1)));
    }
    // if (dateList[dateList.length - 7].month != monthDate.month) {
    //   dateList.removeRange(dateList.length - 7, dateList.length);
    // }
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      child: Column(
        children: <Widget>[
          Padding(
            padding:
                const EdgeInsets.only(left: 8.0, right: 8.0, top: 4, bottom: 4),
            child: Row(
              children: <Widget>[
                Padding(
                  padding: const EdgeInsets.all(8.0),
                  child: Container(
                    height: 38,
                    width: 38,
                    decoration: BoxDecoration(
                      borderRadius:
                          const BorderRadius.all(Radius.circular(24.0)),
                      border: Border.all(
                        color: HotelAppTheme.buildLightTheme().dividerColor,
                      ),
                    ),
                    child: InkWell(
                      borderRadius:
                          const BorderRadius.all(Radius.circular(24.0)),
                      onTap: () {
                        if (mounted) {
                          setState(() {
                            if (getCurMonthIsInMinMaxRange(DateTime(
                                currentMonthDate.year,
                                currentMonthDate.month,
                                0))) {
                              currentMonthDate = DateTime(currentMonthDate.year,
                                  currentMonthDate.month, 0);
                              setListOfDate(currentMonthDate);
                            }
                          });
                        }
                      },
                      child: const Icon(
                        Icons.keyboard_arrow_left,
                        color: Colors.grey,
                      ),
                    ),
                  ),
                ),
                Expanded(
                  child: Center(
                    child: Text(
                      DateFormat('MMMM, yyyy').format(currentMonthDate),
                      style: TextStyle(
                        fontWeight: FontWeight.w500,
                        fontSize: 15.sp,
                        color: Colors.white,
                      ),
                    ),
                  ),
                ),
                Padding(
                  padding: const EdgeInsets.all(8.0),
                  child: Container(
                    height: 38,
                    width: 38,
                    decoration: BoxDecoration(
                      borderRadius:
                          const BorderRadius.all(Radius.circular(24.0)),
                      border: Border.all(
                        color: HotelAppTheme.buildLightTheme().dividerColor,
                      ),
                    ),
                    child: InkWell(
                      borderRadius:
                          const BorderRadius.all(Radius.circular(24.0)),
                      onTap: () {
                        if (mounted) {
                          setState(() {
                            if (getCurMonthIsInMinMaxRange(DateTime(
                                currentMonthDate.year,
                                currentMonthDate.month + 2,
                                0))) {
                              currentMonthDate = DateTime(currentMonthDate.year,
                                  currentMonthDate.month + 2, 0);
                              setListOfDate(currentMonthDate);
                            }
                          });
                        }
                      },
                      child: const Icon(
                        Icons.keyboard_arrow_right,
                        color: Colors.grey,
                      ),
                    ),
                  ),
                ),
              ],
            ),
          ),
          Padding(
            padding: const EdgeInsets.only(right: 8, left: 8, bottom: 8),
            child: Row(
              children: getDaysNameUI(),
            ),
          ),
          Padding(
            padding: const EdgeInsets.only(right: 8, left: 8),
            child: Column(
              children: getDaysNoUI(),
            ),
          ),
        ],
      ),
    );
  }

  List<Widget> getDaysNameUI() {
    final List<Widget> listUI = <Widget>[];
    final weekendList = [5, 6];
    for (int i = 0; i < 7; i++) {
      listUI.add(
        Expanded(
          child: Center(
            child: Text(
              DateFormat('EEE').format(dateList[i]),
              style: TextStyle(
                fontSize: 14.sp,
                fontWeight: FontWeight.w500,
                color: weekendList.contains(i)
                    ? HotelAppTheme.buildLightTheme().primaryColorDark
                    : Colors.white,
              ),
            ),
          ),
        ),
      );
    }
    return listUI;
  }

  List<Widget> getDaysNoUI() {
    final List<Widget> noList = <Widget>[];
    int count = 0;
    for (int i = 0; i < dateList.length / 7; i++) {
      final List<Widget> listUI = <Widget>[];
      for (int i = 0; i < 7; i++) {
        final DateTime date = dateList[count];
        listUI.add(
          Expanded(
            child: AspectRatio(
              aspectRatio: 1.0,
              child: Stack(
                children: <Widget>[
                  Padding(
                    padding: const EdgeInsets.only(top: 3, bottom: 3),
                    child: Padding(
                      padding: EdgeInsets.only(
                          top: 0,
                          bottom: 0,
                          left: isStartDateRadius(date) ? 4 : 0,
                          right: isEndDateRadius(date) ? 4 : 0),
                      child: Container(
                        decoration: BoxDecoration(
                          color: startDate != null && endDate != null
                              ? getIsItStartAndEndDate(date) ||
                                      getIsInRange(date)
                                  ? HotelAppTheme.buildLightTheme()
                                      .primaryColorDark
                                      .withOpacity(0.1)
                                  : Colors.transparent
                              : Colors.transparent,
                          borderRadius: BorderRadius.only(
                            bottomLeft: isStartDateRadius(date)
                                ? Radius.circular(15.r)
                                : const Radius.circular(0.0),
                            topLeft: isStartDateRadius(date)
                                ? Radius.circular(15.r)
                                : const Radius.circular(0.0),
                            topRight: isEndDateRadius(date)
                                ? Radius.circular(15.r)
                                : const Radius.circular(0.0),
                            bottomRight: isEndDateRadius(date)
                                ? Radius.circular(15.r)
                                : const Radius.circular(0.0),
                          ),
                        ),
                      ),
                    ),
                  ),
                  InkWell(
                    borderRadius: const BorderRadius.all(Radius.circular(32.0)),
                    onTap: () {
                      if (currentMonthDate.month == date.month) {
                        final DateTime? minimumDate = widget.minimumDate;
                        final DateTime? maximumDate = widget.maximumDate;
                        if (minimumDate != null && maximumDate != null) {
                          final DateTime newminimumDate = DateTime(
                              minimumDate.year,
                              minimumDate.month,
                              minimumDate.day - 1);
                          final DateTime newmaximumDate = DateTime(
                              maximumDate.year,
                              maximumDate.month,
                              maximumDate.day + 1);
                          if (date.isAfter(newminimumDate) &&
                              date.isBefore(newmaximumDate)) {
                            onDateClick(date);
                          }
                        } else if (minimumDate != null) {
                          final DateTime newminimumDate = DateTime(
                              minimumDate.year,
                              minimumDate.month,
                              minimumDate.day - 1);
                          if (date.isAfter(newminimumDate)) {
                            onDateClick(date);
                          }
                        } else if (maximumDate != null) {
                          final DateTime newmaximumDate = DateTime(
                              maximumDate.year,
                              maximumDate.month,
                              maximumDate.day + 1);
                          if (date.isBefore(newmaximumDate)) {
                            onDateClick(date);
                          }
                        } else {
                          onDateClick(date);
                        }
                      }
                    },
                    child: Padding(
                      padding: const EdgeInsets.all(2),
                      child: Container(
                        decoration: BoxDecoration(
                          color: getIsItStartAndEndDate(date)
                              ? HotelAppTheme.buildLightTheme().primaryColorDark
                              : Colors.transparent,
                          borderRadius: getStartOrEndPoint(date),
                          // border: Border.all(
                          //   color: getIsItStartAndEndDate(date)
                          //       ? Colors.white
                          //       : Colors.transparent,
                          //   width: 2,
                          // ),
                          // boxShadow: getIsItStartAndEndDate(date)
                          //     ? <BoxShadow>[
                          //         BoxShadow(
                          //             color: Colors.grey.withOpacity(0.6),
                          //             blurRadius: 4),
                          //       ]
                          //     : null,
                        ),
                        child: Center(
                          child: Text(
                            '${date.day}',
                            style: ceilStyle(date),
                          ),
                        ),
                      ),
                    ),
                  ),
                  Positioned(
                    bottom: 9,
                    right: 0,
                    left: 0,
                    child: Container(
                      height: 6,
                      width: 6,
                      decoration: BoxDecoration(
                          color: DateTime.now().day == date.day &&
                                  DateTime.now().month == date.month &&
                                  DateTime.now().year == date.year
                              ? getIsInRange(date)
                                  ? Colors.white
                                  : HotelAppTheme.buildLightTheme()
                                      .primaryColorDark
                              : Colors.transparent,
                          shape: BoxShape.circle),
                    ),
                  ),
                ],
              ),
            ),
          ),
        );
        count += 1;
      }
      noList.add(Row(
        mainAxisAlignment: MainAxisAlignment.center,
        mainAxisSize: MainAxisSize.min,
        children: listUI,
      ));
    }
    return noList;
  }

  BorderRadius getStartOrEndPoint(DateTime date) {
    KLogUtil.log([startDate, endDate, KDateUtils.isSome(startDate, endDate)]);
    if (startDate.toString() == endDate.toString()) {
      return BorderRadius.all(
        Radius.circular(15.r),
      );
    } else if (getIsItStart(date)) {
      return BorderRadius.only(
        topLeft: Radius.circular(15.r),
        bottomLeft: Radius.circular(15.r),
      );
    } else {
      return BorderRadius.only(
        topRight: Radius.circular(15.r),
        bottomRight: Radius.circular(15.r),
      );
    }
  }

  // 日期每一格的样式
  TextStyle ceilStyle(DateTime date) {
    // 不能选择日期的样式
    if (!getIsInMinMaxRange(date)) {
      return TextStyle(
        color: Colors.grey.withOpacity(0.6),
        fontSize: MediaQuery.of(context).size.width > 360 ? 14.sp : 16.sp,
        fontWeight:
            getIsItStartAndEndDate(date) ? FontWeight.bold : FontWeight.normal,
      );
    }
    return TextStyle(
        color: getIsItStartAndEndDate(date) || getIsInRange(date)
            ? Colors.white
            : currentMonthDate.month == date.month
                ? Colors.white
                : Colors.grey.withOpacity(0.6),
        fontSize: MediaQuery.of(context).size.width > 360 ? 14.sp : 16.sp,
        fontWeight:
            getIsItStartAndEndDate(date) ? FontWeight.bold : FontWeight.normal);
  }

  bool getIsInMinMaxRange(DateTime date) {
    if (widget.minimumDate != null && widget.maximumDate != null) {
      if (date.isAfter(widget.minimumDate!) &&
          date.isBefore(widget.maximumDate!)) {
        return true;
      }
    }
    return false;
  }

  // 当前月份是否在
  bool getCurMonthIsInMinMaxRange(DateTime tgtMonth) {
    if (widget.minimumDate != null && widget.maximumDate != null) {
      if (tgtMonth.isAfter(DateTime(
              widget.minimumDate!.year, widget.minimumDate!.month, 0)) &&
          tgtMonth.isBefore(DateTime(
              widget.maximumDate!.year, widget.maximumDate!.month + 2, 0))) {
        return true;
      }
    }
    return false;
  }

  bool getIsInRange(DateTime date) {
    if (startDate != null && endDate != null) {
      if (date.isAfter(startDate!) && date.isBefore(endDate!)) {
        return true;
      }
    }
    return false;
  }

  bool getIsItStartAndEndDate(DateTime date) {
    if ((startDate != null &&
            startDate!.day == date.day &&
            startDate!.month == date.month &&
            startDate!.year == date.year) ||
        (endDate != null &&
            endDate!.day == date.day &&
            endDate!.month == date.month &&
            endDate!.year == date.year)) return true;
    return false;
  }

  bool getIsItStart(DateTime date) {
    if (startDate != null &&
        startDate!.day == date.day &&
        startDate!.month == date.month &&
        startDate!.year == date.year) return true;
    return false;
  }

  bool isStartDateRadius(DateTime date) {
    if (startDate != null &&
        startDate!.day == date.day &&
        startDate!.month == date.month) {
      return true;
    } else if (date.weekday == 1) {
      return true;
    } else {
      return false;
    }
  }

  bool isEndDateRadius(DateTime date) {
    if (endDate != null &&
        endDate!.day == date.day &&
        endDate!.month == date.month) {
      return true;
    } else if (date.weekday == 7) {
      return true;
    } else {
      return false;
    }
  }

  void onDateClick(DateTime date) {
    if (startDate == null) {
      startDate = date;
    } else if (startDate != date && endDate == null) {
      endDate = date;
    } else if (startDate!.day == date.day && startDate!.month == date.month) {
      // startDate = null;
      endDate = startDate;
    } else if (endDate != null &&
        endDate!.day == date.day &&
        endDate!.month == date.month) {
      if (endDate != null) {
        startDate = endDate;
      } else {
        endDate = null;
      }
    }
    if (startDate == null && endDate != null) {
      startDate = endDate;
      endDate = null;
    }
    if (startDate != null && endDate != null) {
      if (!endDate!.isAfter(startDate!)) {
        final DateTime d = startDate!;
        startDate = endDate;
        endDate = d;
      }
      if (date.isBefore(startDate!)) {
        startDate = date;
      } else if (date.isAfter(endDate!)) {
        endDate = date;
      } else {
        final int daysToStartDate = startDate!.difference(date).inDays.abs();
        final int daysToEndDate = endDate!.difference(date).inDays.abs();
        daysToStartDate > daysToEndDate ? endDate = date : startDate = date;
      }
    }
    if (mounted) {
      setState(
        () {
          if (startDate != null && endDate != null) {
            try {
              widget.startEndDateChange(startDate!, endDate!);
            } catch (_) {}
          }
          if (startDate != null) {
            try {
              widget.startDateChange(startDate!);
            } catch (_) {}
          }
          if (endDate != null) {
            try {
              widget.endDateChange(endDate!);
            } catch (_) {}
          }
        },
      );
    }
  }
}

hotel_app_theme.dart

import 'package:flutter/material.dart';

class HotelAppTheme {
  static TextTheme _buildTextTheme(TextTheme base) {
    const String fontName = 'WorkSans';
    return base.copyWith(
      displayLarge: base.displayLarge?.copyWith(fontFamily: fontName),
      displayMedium: base.displayMedium?.copyWith(fontFamily: fontName),
      displaySmall: base.displaySmall?.copyWith(fontFamily: fontName),
      headlineMedium: base.headlineMedium?.copyWith(fontFamily: fontName),
      headlineSmall: base.headlineSmall?.copyWith(fontFamily: fontName),
      titleLarge: base.titleLarge?.copyWith(fontFamily: fontName),
      labelLarge: base.labelLarge?.copyWith(fontFamily: fontName),
      bodySmall: base.bodySmall?.copyWith(fontFamily: fontName),
      bodyLarge: base.bodyLarge?.copyWith(fontFamily: fontName),
      bodyMedium: base.bodyMedium?.copyWith(fontFamily: fontName),
      titleMedium: base.titleMedium?.copyWith(fontFamily: fontName),
      titleSmall: base.titleSmall?.copyWith(fontFamily: fontName),
      labelSmall: base.labelSmall?.copyWith(fontFamily: fontName),
    );
  }

  static ThemeData buildLightTheme() {
    // #54D3C2
    // #54D3C2
    // #4677FF
    const Color primaryColor = Color(0xff1C1D1F);
    const Color secondaryColor = Color(0xff1C1D1F);
    const Color primaryColorDark = Color(0xff4677FF);
    final ColorScheme colorScheme = const ColorScheme.light().copyWith(
      primary: primaryColor,
      secondary: secondaryColor,
    );
    final ThemeData base = ThemeData.light();
    return base.copyWith(
      primaryColor: primaryColor,
      primaryColorDark: primaryColorDark,
      indicatorColor: Colors.white,
      splashColor: Colors.white24,
      splashFactory: InkRipple.splashFactory,
      canvasColor: Colors.white,
      // #F6F6F6
      scaffoldBackgroundColor: const Color(0xFFF6F6F6),
      buttonTheme: ButtonThemeData(
        colorScheme: colorScheme,
        textTheme: ButtonTextTheme.primary,
      ),
      textTheme: _buildTextTheme(base.textTheme),
      primaryTextTheme: _buildTextTheme(base.primaryTextTheme),
      platform: TargetPlatform.iOS,
      colorScheme: colorScheme
          .copyWith(background: const Color(0xff1C1D1F))
          // #B00020
          .copyWith(error: const Color(0xFFB00020)),
    );
  }
}

RangePicker.dart  这个文件是使用的地方 这里还使用到了  getx 的组件 从底部弹出

// ignore_for_file: file_names

import 'package:app/gen/assets.gen.dart';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart';
import 'package:intl/intl.dart';

import 'calendar_popup_view.dart';

class RangePicker extends StatefulWidget {
  RangePicker({super.key, required this.apply});

  final Function(DateTime, DateTime) apply;
  @override
  State<RangePicker> createState() => _RangePickerState();
}

class _RangePickerState extends State<RangePicker> {
  DateTime startDate = DateTime.now().subtract(const Duration(days: 90));
  DateTime endDate = DateTime.now();

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: () {
        openCalendarPopupView(context);
      },
      child: Row(
        children: [
          Text(
            "${DateFormat('MM/dd').format(startDate)} - ${DateFormat('MM/dd').format(endDate)}",
            style: TextStyle(
              color: const Color(0xff676970),
              fontWeight: FontWeight.w500,
              fontSize: 12.sp,
            ),
          ),
          SizedBox(
            width: 4.w,
          ),
          Assets.icon.botomArrowhead.image(width: 17.w),
        ],
      ),
    );
  }

  void openCalendarPopupView(BuildContext context) {
    Get.bottomSheet(
      isScrollControlled: true,
      StatefulBuilder(builder: (context, state) {
        return CalendarPopupView(
          state: state,
          minimumDate: DateTime.now().subtract(const Duration(days: 365)),
          maximumDate: DateTime.now(),
          initialEndDate: endDate,
          initialStartDate: startDate,
          onApplyClick: (DateTime startData, DateTime endData) {
            if (mounted) {
              setState(() {
                startDate = startData;
                endDate = endData;
              });
              state(() {
                startDate = startData;
                endDate = endData;
              });
              widget.apply(startDate, endDate);
            }
          },
          onCancelClick: () {},
        );
      }),
    );
  }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/74063.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Android学习之路(2) 设置视图

一、设置视图宽高 ​ 在Android开发中&#xff0c;可以使用LayoutParams类来设置视图&#xff08;View&#xff09;的宽度和高度。LayoutParams是一个用于布局的参数类&#xff0c;用于指定视图在父容器中的位置和大小。 ​ 下面是设置视图宽度和高度的示例代码&#xff1a; …

SpringBoot基于Zookeeper实现分布式锁

文章目录 问题背景前言实现搭建Zookeeper容器引入依赖ZK客户端的配置类ZK客户端的工厂类注入bean构建测试类 问题背景 研究分布式锁&#xff0c;基于ZK实现&#xff0c;需要整合到SpringBoot使用 前言 参考自SpringBoot集成Curator实现Zookeeper基本操作&#xff0c;Zookeeper入…

母牛的故事

一、题目 有一头母牛&#xff0c;它每年年初生一头小母牛。每头小母牛从第四个年头开始&#xff0c;每年年初也生一头小母牛。请编程实现在第n年的时候&#xff0c;共有多少头母牛&#xff1f; Input 输入数据由多个测试实例组成&#xff0c;每个测试实例占一行&#xff0c;包…

CRC 校验码

CRC 校验码 题目解答发送端如何计算商 接收端 题目 假设生成多项式为 G(X)X4X31&#xff0c;要求出二进制序列10110011的CRC校验码 解答 发送端 首先 生成多项式为&#xff1a;G(X)X4X31&#xff0c;改写为二进制比特串为11001(有X的几次方&#xff0c;对应的2的几次方的位…

Android复习(Android基础-四大组件)——Broadcast

1. 广播分类 广播的发送方式&#xff1a;标准广播、有序广播、粘性广播广播的类型&#xff1a;系统广播、本地广播 1.1 标准广播 完全异步&#xff0c;无序的广播发出后&#xff0c;所有的广播接收器几乎都会在同一时间收到消息。&#xff08;异步&#xff09;但是消息无法截…

Mr. Cappuccino的第59杯咖啡——简单手写SpringIOC框架

简单手写SpringIOC框架 环境搭建基于XML方式项目结构项目代码运行结果 基于注解方式项目结构项目代码运行结果 简单手写SpringIOC框架核心原理基于XML方式原理项目结构项目代码运行结果 基于注解方式原理项目结构项目代码运行结果 环境搭建 基于XML方式 项目结构 项目代码 p…

【量化课程】08_1.机器学习量化策略基础实战

文章目录 1. 常用机器学习模型1.1 回归模型1.2 分类模型1.2.1 SVC介绍1.2.2 SVC在量化策略中的应用 2. 机器学习量化策略实现的基本步骤3. 策略实现 1. 常用机器学习模型 1.1 回归模型 线性回归多层感知器回归自适应提升树回归随机森林回归 1.2 分类模型 线性分类支持向量机…

excel 下载方法封装

1.首先需要拿到后端返回的URL下载地址 2.写个下载方法 // url 接口返回的下载地址。例如&#xff1a;https://cancer-research.oss-cn-beijing.aliyuncs.com/yuance-platform-permission/校内共享数据导入模板.xlsx // name 文件名称 例如&#xff1a; 校内共享数据导入模板 /…

反编译微信小程序,可导出uniapp或taro项目

微信小程序反编译&#xff08;全网通用&#xff09; 微信小程序反编译 反编译主要分为四个阶段 操作流程 1. node.js安装 2. node安装模块 3. 开始反编译 4. 导入到微信开发者工具既可运行 微信小程序反编译 当碰到不会写的小程序功能时&#xff0c;正好看到隔壁小程序有类似…

Android学习之路(3) 布局

线性布局LinearLayout 前几个小节的例程中&#xff0c;XML文件用到了LinearLayout布局&#xff0c;它的学名为线性布局。顾名思义&#xff0c;线性布局 像是用一根线把它的内部视图串起来&#xff0c;故而内部视图之间的排列顺序是固定的&#xff0c;要么从左到右排列&#xf…

前后端分离------后端创建笔记(03)前后端对接(下)

本文章转载于【SpringBootVue】全网最简单但实用的前后端分离项目实战笔记 - 前端_大菜007的博客-CSDN博客 仅用于学习和讨论&#xff0c;如有侵权请联系 源码&#xff1a;https://gitee.com/green_vegetables/x-admin-project.git 素材&#xff1a;https://pan.baidu.com/s/…

Java【数据结构】二分查找

&#x1f31e; 题目&#xff1a; &#x1f30f;在有序数组A中&#xff0c;查找目标值target &#x1f30f;如果找到返回索引 &#x1f30f;如果找不到返回-1 算法描述解释前提给定一个内含n个元素的有序数组A&#xff0c;满足A0<A1<A2<<An-1,一个待查值target1设…

游戏中的UI适配

引用参考&#xff1a;感谢GPT UI适配原理以及常用方案 游戏UI适配是确保游戏界面在不同设备上以不同的分辨率、屏幕比例和方向下正常显示的关键任务。下面是一些常见的游戏UI适配方案&#xff1a; 1.分辨率无关像素&#xff08;Resolution-Independent Pixels&#xff09;&a…

【EI/SCOPUS检索】第三届计算机视觉、应用与算法国际学术会议(CVAA 2023)

第三届计算机视觉、应用与算法国际学术会议&#xff08;CVAA 2023) The 3rd International Conference on Computer Vision, Application and Algorithm 2023年第三届计算机视觉、应用与算法国际学术会议&#xff08;CVAA 2023&#xff09;主要围绕计算机视觉、计算机应用、计…

Python程序设计基础:函数(二)

文章目录 一、lambda()函数二、递归函数三、变量的作用域 一、lambda()函数 lambda()函数是一种简便的&#xff0c;将函数定义在同一行的函数方法。lambda()实际上生成了一个函数对象&#xff08;匿名函数&#xff09;&#xff0c;它主要用于需要函数对象作为参数或函数比较简…

ChatGPT能代替搜索引擎吗?ChatGPT和搜索引擎有什么区别?

ChatGPT和搜索引擎是两种在信息获取和交流中常用的工具&#xff0c;ChatGPT是一种基于人工智能技术的聊天机器人&#xff0c;而搜索引擎是一种在互联网上搜索信息的工具。尽管它们都是依托互联网与信息获取和交流有关&#xff0c;部分功能重合&#xff0c;但在很多方面存在着明…

并发编程 - 线程池中的常见面试题

目录 1. 线程池相比于线程有什么优点 2. 线程池的参数有哪些 3. 线程工厂有什么用 4. 说一下线程的优先级 5. 说一下线程池的执行流程 6. 线程池的拒绝策略有哪些 7. 如何实现自定义拒绝策略 8. 如何判断线程池中的任务是否执行完成 1. 线程池相比于线程有什么优点 有…

2023.8.14论文阅读

文章目录 ESPNet: Efficient Spatial Pyramid of Dilated Convolutions for Semantic Segmentation摘要本文方法实验结果 DeepFusion: Lidar-Camera Deep Fusion for Multi-Modal 3D Object Detection摘要本文方法实验结果 ESPNet: Efficient Spatial Pyramid of Dilated Convo…

ASR 语音识别接口封装和分析

这个文档主要是介绍一下我自己封装了 6 家厂商的短语音识别和实时流语音识别接口的一个包&#xff0c;以及对这些接口的一个对比。分别是&#xff0c;阿里&#xff0c;快商通&#xff0c;百度&#xff0c;腾讯&#xff0c;科大&#xff0c;字节。 zxmfke/asrfactory (github.c…