flutter 手写日历组件

news2024/12/24 20:51:49

先看效果

 直接上代码

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: () {},
        );
      }),
    );
  }
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

翻出了我当时学习的笔记来了html

php&#xff1a;高级语言 web应用程序 万维网 浏览器中查看 apache&#xff1a;服务器 mysql&#xff1a;数据库 html 标签 css&#xff1a;层叠样式表 javascript&#xff1a;客户端脚本 js jquery mysql数据库基础 php语法基础 面向对象&#xff08;物件&#xff09; smar…

WebRTC | 实现数据流的一对一通信

目录 一、浏览器对WebRTC的支持 二、MediaStream与MediaStreamTrack 三、RTCPeerConnection 1. RTCPeerConnection与本地音视频数据绑定 2. 媒体协商SDP 3. ICE &#xff08;1&#xff09;Candidate信息 &#xff08;2&#xff09;WebRTC收集Candidate &#xff08;3&…

LOTO示波器实测过压保护芯片LP5300工作效果

过压保护电路是电子产品设置中经常要用到的&#xff0c;以前都是用分立元件搭的各种经典电路&#xff0c;最近LOTO虚拟示波器客户推荐了一款很便宜的集成的过压保护芯片LP5300&#xff0c;体积很小&#xff0c;使用简单&#xff0c;外接两个电容就可以了&#xff0c;下图是它的…

linux自定义网络访问规则

1.更改防火墙默认区域为trusted firewall-cmd --set-default-zonetrusted 2.新建一个zone&#xff0c;将想要访问本机80端口的ip&#xff0c;如&#xff1a;192.168.3.99 &#xff0c;添加的这个zone中&#xff0c;同时在这个zone中放行80端口。 firewall-cmd --permanent --ne…

django中使用bootstrap-datepicker时间插件

1、插件的下载 Bootstrap Datepicker是一款基 于Bootstrap框架的日期选择控件&#xff0c;可以方便地在Web应用中添加可交互的日期选择功能。Bootstrap Datepicker拥有丰富的选项和API,支持多种日期格式&#xff0c;可以自定义样式并支持各种语言。 Bootstrap Datepicker 依赖…

DolphinScheduler集群搭建详细笔记

1.DolphinScheduler Cluster部署 1.1 集群部署规划 集群模式下&#xff0c;可配置多个Master及多个Worker。通常可配置2~3个Master&#xff0c;若干个Worker。由于集群资源有限&#xff0c;此处配置一个Master&#xff0c;三个Worker&#xff0c;集群规划如下。 主机名ip服务…

Hybrid App 技术发展的趋势解读

Hybrid这个词&#xff0c;在App开发领域&#xff0c;相信大家都不陌生。Hybrid App是指介于web-app、native-app这两者之间的app&#xff0c;它虽然看上去是一个Native App&#xff0c;但只有一个UI WebView&#xff0c;里面访问的是一个Web App。Hybrid在移动领域的发展&#…

为什么要从 Splashtop Business Access 升级到 Enterprise?

远程工作只是偶尔为之的时代已经一去不复返了。它已成为一种战略必需品&#xff0c;使企业能够利用全球人才库&#xff0c;提供灵活的工作安排&#xff0c;并在不可预测的情况下确保业务连续性。 拥有安全、可靠、高效的远程访问解决方案已变得至关重要。Splashtop Business A…

【学习】若依源码(前后端分离版)之 “ 用户的权限注解”

大型纪录片&#xff1a;学习若依源码&#xff08;前后端分离版&#xff09;之 “ 用户的权限注解” 前言前端部分后端部分公开接口 结语 前言 接着来聊聊若依前后端分离版的权限注解吧。若依前后端分离版的权限注解是一种基于Spring Security和Vue的权限管理系统&#xff0c;它…

快速获得图像中像素值的小工具

之前项目中为了做lka中获得rgb图像信息&#xff0c;网上大多方案是确定相关的区域然后输出像素值&#xff0c;这个方法太麻烦&#xff0c;做了一个简单的使用鼠标点击图片某区域&#xff0c;然后直接在终端输出该区域的像素值。下面是源码&#xff1a; import cv2 import matp…

解析湖仓一体的支撑技术及实践路径

自2021年“湖仓一体”首次写入Gartner数据管理领域成熟度模型报告以来&#xff0c;随着企业数字化转型的不断深入&#xff0c;“湖仓一体”作为新型的技术受到了前所未有的关注&#xff0c;越来越多的企业视“湖仓一体” 为数字化转型的重要基础设施。 01 数据平台的发展历程…

kubernetes高性能存储-piraeus简介

piraeus简介 Piraeus 是面向 Kubernetes 的高性能、高可用性、简单、安全且与云无关的云原生存储解决方案&#xff0c;号称性能和稳定性都优于 Ceph/OpenEBS/Longhorn 等项目。Piraeus 对应的商业产品为LINSTOR 。 众所周知&#xff0c;本地存储具有高性能的优势&#xff0c;…

基于Python 简易实现接口测试自动化

目录 实现思路 统筹脚本 请求封装 日志封装 结果比对 结果邮件 用例获取及数据格式化 请求url转换 测试用例excel结构 测试报告 邮件接收结果 资料获取方法 实现思路 使用excel管理用例用例信息&#xff0c;requests模块发送http请求&#xff0c;实现了记录日志&…

科聪控制系统六大行业典型应用案例合集

01. 纺织行业 科聪移动机器人通用控制系统赋能无人接丝AGV实现丝盘自动化上下料 应用难点&#xff1a;无人接丝AGV是纺织行业无人工厂重要环节之一&#xff0c;这个环节对机器人到点精度要求非常高&#xff0c;无人接丝AGV的到位精度&#xff0c;必须确保“丝级”的准确无误&…

geeemap学习总结(2)——地图底图应用

1. 加载库中已有图层 import os os.environ[HTTP_PROXY] http://127.0.0.1:8001 os.environ[HTTPS_PROXY] http://127.0.0.1:8001 # 设置中心位置/地图层级/图层加载高度&#xff0c;加载图层 import geemap Mapgeemap.Map(center[40, 100], zoom4, height600) Map# 添加已经…

Javascript 正则

基本语法 定义 JavaScript种正则表达式有两种定义方式 构造函数 var regnew RegExp(<%[^%>]%>,g);字面量 var reg/<%[^%>]%>/g;g&#xff1a; global&#xff0c;全文搜索&#xff0c;默认搜索到第一个结果接停止i&#xff1a;ingore case&#xff0c;忽略…

Linux(进程地址空间)

进程地址空间 程序地址空间进程地址空间 程序地址空间 在Linux环境下&#xff0c;我们可以对上述程序空间地址进行验证&#xff1a; 运行程序&#xff0c;可以看到&#xff0c;我们就可以很好看出程序的地址空间的排布了&#xff1a; 进程地址空间 严格来说&#xff0c;我们…

免费商用图片素材网站,4K高清无水印。

推荐6个图片素材网站&#xff0c;免费下载&#xff0c;还可以商用&#xff0c;希望对大家有帮助。 菜鸟图库 美女图片|手机壁纸|风景图片大全|高清图片素材下载网 - 菜鸟图库 网站主要是为新手设计师提供免费素材的&#xff0c;素材的质量都很高&#xff0c;类别也很多&#x…

NGINX组件(rewrite)

一、location匹配的规则和优先级&#xff08;*&#xff09; URI&#xff1a;统一资源标识符&#xff0c;是一种字符串标识&#xff0c;用于标识抽象的或者是物理资源&#xff1b;如&#xff1a;文件、图片、视频等 nginx中的URI匹配的是&#xff1a;网址”/“后的路径 如&…

17 spring项目——登录拦截器

经实验发现&#xff0c;当访问拦截器拦截的地址的时候都会经过拦截器。在拦截器中&#xff0c;返回true则放行&#xff0c;允许访问该地址&#xff1b;返回false&#xff0c;则拦截&#xff0c;不允许访问该地址&#xff0c;但可以在return前去设置要跳转的地址。 拦截器可以拦…