美文网首页
Flutter 之时间日期选择器(DatePicker,Time

Flutter 之时间日期选择器(DatePicker,Time

作者: maskerII | 来源:发表于2022-05-19 21:01 被阅读0次

    showDatePicker、showTimePicker 是 flutter 提供的日期选择器弹框。

    1. showDatePicker

    Future<DateTime?> showDatePicker({
      required BuildContext context,
      required DateTime initialDate,
      required DateTime firstDate,
      required DateTime lastDate,
      DateTime? currentDate,
      DatePickerEntryMode initialEntryMode = DatePickerEntryMode.calendar,
      SelectableDayPredicate? selectableDayPredicate,
      String? helpText,
      String? cancelText,
      String? confirmText,
      Locale? locale,
      bool useRootNavigator = true,
      RouteSettings? routeSettings,
      TextDirection? textDirection,
      TransitionBuilder? builder,
      DatePickerMode initialDatePickerMode = DatePickerMode.day,
      String? errorFormatText,
      String? errorInvalidText,
      String? fieldHintText,
      String? fieldLabelText,
    })
    

    showDatePicker 属性

    showDatePicker属性 介绍
    context @required BuildContext,上下文 context
    initialDate @required DateTime,日历初始化日期
    firstDate @required DateTime,日历开始日期
    lastDate @required DateTime,日历结束日期
    currentDate DateTime 当前日期
    initialEntryMode DatePickerEntryMode 日历弹框样式 calendar: 默认显示日历,可切换成输入模式,input:默认显示输入模式,可切换到日历,calendarOnly:只显示日历,inputOnly:只显示输入模式
    selectableDayPredicate (DateTime dayTime){ return true;} 一个返回 bool 值的函数,自定义哪些日期可选
    helpText 左上角文字
    cancelText 取消按钮文字
    confirmText 确认按钮文字
    locale 地区设置,以后多语言部分在详解
    useRootNavigator 是否使用根导航,默认为 true,官方文档也没做详解,暂时没用到
    routeSettings 路由设置,官方文档也没做详解,暂时没用到
    textDirection 水平方向 显示方向 默认 ltr
    builder 创建器,和直接创建基本一致,可以定制主题
    initialDatePickerMode DatePickerMode.day 与 DatePickerMode.year 两种, DatePickerMode.day 默认显示某一天的选择界面,可切换到年份选择界面, DatePickerMode.year 默认显示年份,可切换到某一天的选择界面
    errorFormatText 格式错误是下方提示
    fieldHintText 输入框默认提示语
    fieldLabelText 输入框上方提示语
    errorInvalidText 输入了不在 first 与 last 之间的日期提示语

    示例1-日期选择弹窗

    
    Future<DateTime?> _showDatePickerForDay(BuildContext context) {
      return showDatePicker(
        context: context, // 上下文
        initialDate: DateTime(2022, 5, 20), // 初始化选中日期
        firstDate: DateTime(2022, 5), // 开始日期
        lastDate: DateTime(2022, 7), // 结束日期
        currentDate: DateTime.now(), // 当前日期
        initialEntryMode: DatePickerEntryMode
            .calendar, // 日历弹框样式 calendar: 默认显示日历,可切换成输入模式,input:默认显示输入模式,可切换到日历,calendarOnly:只显示日历,inputOnly:只显示输入模式
        selectableDayPredicate: (dayTime) {
          // 自定义哪些日期可选
          if (dayTime == DateTime(2022, 5, 6) ||
              dayTime == DateTime(2022, 6, 8)) {
            return false;
          }
          return true;
        },
        helpText: "请选择日期", // 左上角提示文字
        cancelText: "Cancel", // 取消按钮 文案
        confirmText: "OK", // 确认按钮 文案
        initialDatePickerMode: DatePickerMode.day, // 日期选择模式 默认为天
        useRootNavigator: true, // 是否使用根导航器
        errorFormatText: "输入日期格式有误,请重新输入", // 输入日期 格式错误提示
        errorInvalidText: "输入日期不合法,请重新输入", // 输入日期 不在first 与 last 之间提示
        fieldLabelText: "输入所选日期", // 输入框上方 提示
        fieldHintText: "请输入日期", // 输入框为空时提示
        textDirection: TextDirection.ltr, // 水平方向 显示方向 默认 ltr
      );
    }
    
    
    120.gif

    示例2 - 年份选择弹窗

    
    Future<DateTime?> _showDatePickerForYear(BuildContext context) {
      return showDatePicker(
        context: context,
        initialDate: DateTime(1991), // 初始化选中日期
        firstDate: DateTime(1990), // 开始日期
        lastDate: DateTime(2025), // 结束日期
        currentDate: DateTime.now(), // 当前日期
        initialEntryMode: DatePickerEntryMode.input, // 日历弹框模式
        selectableDayPredicate: (daytime) {
          // 自定义哪些日期可选
          if (daytime == DateTime(2000)) {
            return false;
          }
          return true;
        },
        initialDatePickerMode: DatePickerMode.year, // 日期选择模式 默认为天
        helpText: "请选择年份", // 左上角提示
        cancelText: "Cancel", // 取消按钮 文案
        confirmText: "OK", // 确认按钮 文案
        useRootNavigator: true, // 是否使用根导航器
        errorFormatText: "输入格式有误", // 输入日期 格式错误提示
        errorInvalidText: "输入年份不合法", // 输入日期 不在first 与 last 之间提示
        fieldHintText: "请输入年份", // 输入框为空时提示
        fieldLabelText: "输入正确的年份", // 输入框上方 提示
        textDirection: TextDirection.ltr, // 水平方向 显示方向 默认 ltr
      );
    }
    
    
    121.gif

    示例3 - 仅显示日历选择

    
    Future<DateTime?> _showDatePickerForCalendarOnly(BuildContext context) {
      return showDatePicker(
        context: context, // 上下文
        initialDate: DateTime(2022, 5, 20), // 初始化选中日期
        firstDate: DateTime(2022, 5), // 开始日期
        lastDate: DateTime(2022, 7), // 结束日期
        currentDate: DateTime.now(), // 当前日期
        initialEntryMode: DatePickerEntryMode
            .calendarOnly, // 日历弹框样式 calendar: 默认显示日历,可切换成输入模式,input:默认显示输入模式,可切换到日历,calendarOnly:只显示日历,inputOnly:只显示输入模式
        selectableDayPredicate: (dayTime) {
          // 自定义哪些日期可选
          if (dayTime == DateTime(2022, 5, 6) || dayTime == DateTime(2022, 6, 8)) {
            return false;
          }
          return true;
        },
        helpText: "请选择日期", // 左上角提示文字
        cancelText: "Cancel", // 取消按钮 文案
        confirmText: "OK", // 确认按钮 文案
        initialDatePickerMode: DatePickerMode.day, // 日期选择模式 默认为天
        useRootNavigator: true, // 是否使用根导航器
        textDirection: TextDirection.ltr, // 水平方向 显示方向 默认 ltr
      );
    }
    
    
    
    image.png

    示例4 - 仅显示日历输入

    
    Future<DateTime?> _showDatePickerForInputOnly(BuildContext context) {
      return showDatePicker(
        context: context,
        initialDate: DateTime(1991), // 初始化选中日期
        firstDate: DateTime(1990), // 开始日期
        lastDate: DateTime(2025), // 结束日期
        currentDate: DateTime.now(), // 当前日期
        initialEntryMode: DatePickerEntryMode.inputOnly, // 日历弹框模式
        selectableDayPredicate: (daytime) {
          // 自定义哪些日期可选
          if (daytime == DateTime(2000)) {
            return false;
          }
          return true;
        },
        initialDatePickerMode: DatePickerMode.year, // 日期选择模式 默认为天
        helpText: "请选择年份", // 左上角提示
        cancelText: "Cancel", // 取消按钮 文案
        confirmText: "OK", // 确认按钮 文案
        useRootNavigator: true, // 是否使用根导航器
        errorFormatText: "输入格式有误", // 输入日期 格式错误提示
        errorInvalidText: "输入年份不合法", // 输入日期 不在first 与 last 之间提示
        fieldHintText: "请输入年份", // 输入框为空时提示
        fieldLabelText: "输入正确的年份", // 输入框上方 提示
        textDirection: TextDirection.ltr, // 水平方向 显示方向 默认 ltr
      );
    }
    
    
    image.png

    示例5 - 日期选择器主题设置

    
    Future<DateTime?> _showDatePickerForTheme(BuildContext context) {
      return showDatePicker(
        context: context, // 上下文
        initialDate: DateTime(2022, 5, 20), // 初始化选中日期
        firstDate: DateTime(2022, 5), // 开始日期
        lastDate: DateTime(2022, 7), // 结束日期
        currentDate: DateTime.now(), // 当前日期
        initialEntryMode: DatePickerEntryMode
            .calendarOnly, // 日历弹框样式 calendar: 默认显示日历,可切换成输入模式,input:默认显示输入模式,可切换到日历,calendarOnly:只显示日历,inputOnly:只显示输入模式
        selectableDayPredicate: (dayTime) {
          // 自定义哪些日期可选
          if (dayTime == DateTime(2022, 5, 6) || dayTime == DateTime(2022, 6, 8)) {
            return false;
          }
          return true;
        },
        builder: (context, child) {
          return Theme(
            data: ThemeData(
              primarySwatch: Colors.amber,
            ),
            child: child!,
          );
        },
        helpText: "请选择日期", // 左上角提示文字
        cancelText: "Cancel", // 取消按钮 文案
        confirmText: "OK", // 确认按钮 文案
        initialDatePickerMode: DatePickerMode.day, // 日期选择模式 默认为天
        useRootNavigator: true, // 是否使用根导航器
        textDirection: TextDirection.ltr, // 水平方向 显示方向 默认 ltr
      );
    }
    
    
    image.png

    2. showTimePicker

    Future<TimeOfDay?> showTimePicker({
      required BuildContext context,
      required TimeOfDay initialTime,
      TransitionBuilder? builder,
      bool useRootNavigator = true,
      TimePickerEntryMode initialEntryMode = TimePickerEntryMode.dial,
      String? cancelText,
      String? confirmText,
      String? helpText,
      String? errorInvalidText,
      String? hourLabelText,
      String? minuteLabelText,
      RouteSettings? routeSettings,
      EntryModeChangeCallback? onEntryModeChanged,
    })
    

    showTimePicker属性

    showTimePicker属性 介绍
    context 上下文
    initialTime 初始化时间 初始化选中时间
    builder 构造器
    useRootNavigator 是否使用根导航,默认为 true
    initialEntryMode 时间选择模式 TimePickerEntryMode , dial input,默认dial
    cancelText 取消按钮 文案
    confirmText 确认按钮 文案
    helpText 左上角提示语
    errorInvalidText 输入时间不合法提示语
    hourLabelText 小时 提示语
    minuteLabelText 分钟 提示语
    RouteSettings 路由配置
    onEntryModeChanged 时间选择模式变化回调
    image.png image.png

    示例

    Future<TimeOfDay?> _showTimePicker(BuildContext context) {
      return showTimePicker(
        context: context, // 上下文
        initialTime: TimeOfDay.now(), // 初始化时间
        initialEntryMode: TimePickerEntryMode.input, // 时间选择模式 dial input
        useRootNavigator: true, // 是否使用根导航 默认true
        cancelText: "取消", // 取消按钮 文案
        confirmText: "确认", // 确认按钮 文案
        helpText: "请选择时间", // 左上角提示语
        errorInvalidText: "输入时间不合法", // 属于时间不合法 提示语
        hourLabelText: "小时", // 小时 提示语
        minuteLabelText: "分钟", // 分钟 提示语
        // 时间选择模式变化 回调
        onEntryModeChanged: (mode) {
          print("Mode Changed $mode");
        },
      );
    }
    
    122.gif

    3. showDatePicker 原理

    showDatePicker 也是弹出对话框,内部实际上是调用showDialog。showDialog的builder用于创建DatePickerDialog。

    showDatePicker 核心代码

    ...
     Widget dialog = DatePickerDialog(
        initialDate: initialDate,
        firstDate: firstDate,
        lastDate: lastDate,
        currentDate: currentDate,
        initialEntryMode: initialEntryMode,
        selectableDayPredicate: selectableDayPredicate,
        helpText: helpText,
        cancelText: cancelText,
        confirmText: confirmText,
        initialCalendarMode: initialDatePickerMode,
        errorFormatText: errorFormatText,
        errorInvalidText: errorInvalidText,
        fieldHintText: fieldHintText,
        fieldLabelText: fieldLabelText,
      );
    ...
      return showDialog<DateTime>(
        context: context,
        useRootNavigator: useRootNavigator,
        routeSettings: routeSettings,
        builder: (BuildContext context) {
          return builder == null ? dialog : builder(context, dialog);
        },
      );
    ...
    

    DatePickerDialog 核心代码

    
    final header = SizedBox(
      ...
      ...
    );
    
    final picker = CalendarDatePicker(
      ...
      ...
    );
    
    final Widget actions = Container(
      ...
      ...
    );
    
    return Dialog(
      ...
      child: AnimatedContainer(
        ...
        child: MediaQuery(
          ...
          child: Builder(builder: (BuildContext context) {
            switch (orientation) {
              case Orientation.portrait:
                return Column(
                  mainAxisSize: MainAxisSize.min,
                  crossAxisAlignment: CrossAxisAlignment.stretch,
                  children: <Widget>[
                    header,
                    Expanded(child: picker),
                    actions,
                  ],
                );
              case Orientation.landscape:
                return Row(
                  ...
    
                );
            }
          }),
        ),
      ),
    );
    
    
    
    

    showTimePicker 和 showDatePicker 类似,也是调用showDialog,只不过showTimePicker build的是TimePickerDialog。

    自定义DatePicker MSCustomDatePicker

    
    class MSCustomDatePicker extends StatelessWidget {
      MSCustomDatePicker({
        Key? key,
        required this.initialDate,
        required this.firstDate,
        required this.lastDate,
        this.helpText,
        this.cancelText = "取消",
        this.sureText = "确定",
      });
    
      final DateTime initialDate;
      final DateTime firstDate;
      final DateTime lastDate;
      final String? helpText;
      final String cancelText;
      final String sureText;
    
      DateTime? _chooseDateTime;
    
      @override
      Widget build(BuildContext context) {
        _chooseDateTime = initialDate;
        final ValueNotifier<DateTime> _chooseDateValueNoti =
            ValueNotifier<DateTime>(initialDate);
    
        final double textScaleFactor =
            math.min(MediaQuery.of(context).textScaleFactor, 1.3);
        final Size _calendarPortraitDialogSize = Size(330.0, 518.0);
        final Size dialogSize = _calendarPortraitDialogSize * textScaleFactor;
    
        final MaterialLocalizations localizations =
            MaterialLocalizations.of(context);
    
        final header = SizedBox(
          height: 120,
          child: Material(
            color: Theme.of(context).primaryColor,
            child: Padding(
              padding: EdgeInsetsDirectional.only(start: 24, end: 12),
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  SizedBox(height: 16),
                  Text(
                    helpText ?? "",
                    textAlign: TextAlign.center,
                    style: TextStyle(color: Colors.grey[200]),
                  ),
                  const Flexible(child: SizedBox(height: 38)),
                  ValueListenableBuilder<DateTime>(
                    valueListenable: _chooseDateValueNoti,
                    builder: (context, datetime, child) {
                      final String dateText =
                          localizations.formatMediumDate(datetime);
                      return Text(
                        dateText,
                        textScaleFactor: 2.0,
                        style: TextStyle(color: Colors.white),
                      );
                    },
                  ),
                ],
              ),
            ),
          ),
        );
    
        final picker = CalendarDatePicker(
          initialDate: initialDate,
          firstDate: firstDate,
          lastDate: lastDate,
          currentDate: DateTime.now(),
          onDateChanged: (datetime) {
            _chooseDateTime = datetime;
            _chooseDateValueNoti.value = datetime;
            print("DateChanged $datetime");
          },
        );
    
        final Widget actions = Container(
          alignment: AlignmentDirectional.centerEnd,
          constraints: const BoxConstraints(minHeight: 52.0),
          padding: const EdgeInsets.symmetric(horizontal: 8),
          child: OverflowBar(
            spacing: 8,
            children: <Widget>[
              TextButton(
                onPressed: () {
                  Navigator.of(context).pop();
                },
                child: Text(cancelText),
              ),
              TextButton(
                onPressed: () {
                  Navigator.of(context).pop(_chooseDateTime);
                },
                child: Text(sureText),
              ),
            ],
          ),
        );
    
        return Dialog(
          insetPadding:
              const EdgeInsets.symmetric(horizontal: 16.0, vertical: 24.0),
          child: AnimatedContainer(
            duration: Duration(milliseconds: 150),
            height: dialogSize.height,
            width: dialogSize.width,
            curve: Curves.easeIn,
            child: Builder(
              builder: (context) {
                return Column(
                  mainAxisSize: MainAxisSize.min,
                  crossAxisAlignment: CrossAxisAlignment.stretch,
                  children: [
                    header,
                    Expanded(child: picker),
                    actions,
                  ],
                );
              },
            ),
          ),
        );
      }
    }
    
    

    使用自定义的DatePicker

    
    class MSCustomDatePickerDemo extends StatelessWidget {
      const MSCustomDatePickerDemo({Key? key}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(title: Text("MSCustomDatePickerDemo")),
          body: Padding(
            padding: EdgeInsets.all(24),
            child: ElevatedButton(
              child: Text("CustomDatePicker"),
              onPressed: () async {
                DateTime? _dateTime = await _showCustomDatePicker(context);
                if (_dateTime == null) {
                  print("取消选择");
                } else {
                  print("选择 $_dateTime");
                }
              },
            ),
          ),
        );
      }
    
      Future<DateTime?> _showCustomDatePicker(BuildContext context) {
        return showDialog<DateTime>(
          context: context,
          builder: (context) {
            return MSCustomDatePicker(
              initialDate: DateTime.now(),
              firstDate: DateTime(2021, 10, 10),
              lastDate: DateTime(2022, 10, 10),
              helpText: "请选择日期",
            );
          },
        );
      }
    }
    
    
    124.gif

    4. Demo

    MSDateAndTimePickerDemo

    class MSDateAndTimePickerDemo extends StatelessWidget {
      const MSDateAndTimePickerDemo({Key? key}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(title: Text("DateAndTimePickerDemo")),
          body: Padding(
            padding: EdgeInsets.all(16),
            child: SingleChildScrollView(
              child: Center(
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.center,
                  children: [
                    ElevatedButton(
                      onPressed: () async {
                        DateTime? _dateTime = await _showDatePickerForDay(context);
                        if (_dateTime == null) {
                          print("取消选择");
                        } else {
                          print("选择 $_dateTime");
                        }
                      },
                      child: Text("DatePicker-Day"),
                    ),
                    ElevatedButton(
                      onPressed: () async {
                        DateTime? _dateTime = await _showDatePickerForYear(context);
                        if (_dateTime == null) {
                          print("取消选择");
                        } else {
                          print("选择 $_dateTime");
                        }
                      },
                      child: Text("DatePicker-Year"),
                    ),
                    ElevatedButton(
                      onPressed: () async {
                        DateTime? _dateTime =
                            await _showDatePickerForCalendarOnly(context);
                        if (_dateTime == null) {
                          print("取消选择");
                        } else {
                          print("选择 $_dateTime");
                        }
                      },
                      child: Text("DatePicker-Day-CalendarOnly"),
                    ),
                    ElevatedButton(
                      onPressed: () async {
                        DateTime? _dateTime =
                            await _showDatePickerForInputOnly(context);
                        if (_dateTime == null) {
                          print("取消选择");
                        } else {
                          print("选择 $_dateTime");
                        }
                      },
                      child: Text("DatePicker-Year-InputOnly"),
                    ),
                    ElevatedButton(
                      onPressed: () async {
                        DateTime? _dateTime =
                            await _showDatePickerForTheme(context);
                        if (_dateTime == null) {
                          print("取消选择");
                        } else {
                          print("选择 $_dateTime");
                        }
                      },
                      child: Text("DatePicker-Day-Theme"),
                    ),
                    ElevatedButton(
                      onPressed: () async {
                        TimeOfDay? _dateTime = await _showTimePicker(context);
                        if (_dateTime == null) {
                          print("取消选择");
                        } else {
                          print("选择 $_dateTime");
                        }
                      },
                      child: Text("DatePicker-Time"),
                    ),
                  ],
                ),
              ),
            ),
          ),
        );
      }
    
      Future<DateTime?> _showDatePickerForDay(BuildContext context) {
        return showDatePicker(
          context: context, // 上下文
          initialDate: DateTime(2022, 5, 20), // 初始化选中日期
          firstDate: DateTime(2022, 5), // 开始日期
          lastDate: DateTime(2022, 7), // 结束日期
          currentDate: DateTime.now(), // 当前日期
          initialEntryMode: DatePickerEntryMode
              .calendar, // 日历弹框样式 calendar: 默认显示日历,可切换成输入模式,input:默认显示输入模式,可切换到日历,calendarOnly:只显示日历,inputOnly:只显示输入模式
          selectableDayPredicate: (dayTime) {
            // 自定义哪些日期可选
            if (dayTime == DateTime(2022, 5, 6) ||
                dayTime == DateTime(2022, 6, 8)) {
              return false;
            }
            return true;
          },
          helpText: "请选择日期", // 左上角提示文字
          cancelText: "Cancel", // 取消按钮 文案
          confirmText: "OK", // 确认按钮 文案
          initialDatePickerMode: DatePickerMode.day, // 日期选择模式 默认为天
          useRootNavigator: true, // 是否使用根导航器
          errorFormatText: "输入日期格式有误,请重新输入", // 输入日期 格式错误提示
          errorInvalidText: "输入日期不合法,请重新输入", // 输入日期 不在first 与 last 之间提示
          fieldLabelText: "输入所选日期", // 输入框上方 提示
          fieldHintText: "请输入日期", // 输入框为空时提示
          textDirection: TextDirection.ltr, // 水平方向 显示方向 默认 ltr
        );
      }
    
      Future<DateTime?> _showDatePickerForYear(BuildContext context) {
        return showDatePicker(
          context: context,
          initialDate: DateTime(1991), // 初始化选中日期
          firstDate: DateTime(1990), // 开始日期
          lastDate: DateTime(2025), // 结束日期
          currentDate: DateTime.now(), // 当前日期
          initialEntryMode: DatePickerEntryMode.input, // 日历弹框模式
          selectableDayPredicate: (daytime) {
            // 自定义哪些日期可选
            if (daytime == DateTime(2000)) {
              return false;
            }
            return true;
          },
          initialDatePickerMode: DatePickerMode.year, // 日期选择模式 默认为天
          helpText: "请选择年份", // 左上角提示
          cancelText: "Cancel", // 取消按钮 文案
          confirmText: "OK", // 确认按钮 文案
          useRootNavigator: true, // 是否使用根导航器
          errorFormatText: "输入格式有误", // 输入日期 格式错误提示
          errorInvalidText: "输入年份不合法", // 输入日期 不在first 与 last 之间提示
          fieldHintText: "请输入年份", // 输入框为空时提示
          fieldLabelText: "输入正确的年份", // 输入框上方 提示
          textDirection: TextDirection.ltr, // 水平方向 显示方向 默认 ltr
        );
      }
    
      Future<DateTime?> _showDatePickerForCalendarOnly(BuildContext context) {
        return showDatePicker(
          context: context, // 上下文
          initialDate: DateTime(2022, 5, 20), // 初始化选中日期
          firstDate: DateTime(2022, 5), // 开始日期
          lastDate: DateTime(2022, 7), // 结束日期
          currentDate: DateTime.now(), // 当前日期
          initialEntryMode: DatePickerEntryMode
              .calendarOnly, // 日历弹框样式 calendar: 默认显示日历,可切换成输入模式,input:默认显示输入模式,可切换到日历,calendarOnly:只显示日历,inputOnly:只显示输入模式
          selectableDayPredicate: (dayTime) {
            // 自定义哪些日期可选
            if (dayTime == DateTime(2022, 5, 6) ||
                dayTime == DateTime(2022, 6, 8)) {
              return false;
            }
            return true;
          },
          helpText: "请选择日期", // 左上角提示文字
          cancelText: "Cancel", // 取消按钮 文案
          confirmText: "OK", // 确认按钮 文案
          initialDatePickerMode: DatePickerMode.day, // 日期选择模式 默认为天
          useRootNavigator: true, // 是否使用根导航器
          textDirection: TextDirection.ltr, // 水平方向 显示方向 默认 ltr
        );
      }
    
      Future<DateTime?> _showDatePickerForInputOnly(BuildContext context) {
        return showDatePicker(
          context: context,
          initialDate: DateTime(1991), // 初始化选中日期
          firstDate: DateTime(1990), // 开始日期
          lastDate: DateTime(2025), // 结束日期
          currentDate: DateTime.now(), // 当前日期
          initialEntryMode: DatePickerEntryMode.inputOnly, // 日历弹框模式
          selectableDayPredicate: (daytime) {
            // 自定义哪些日期可选
            if (daytime == DateTime(2000)) {
              return false;
            }
            return true;
          },
          initialDatePickerMode: DatePickerMode.year, // 日期选择模式 默认为天
          helpText: "请选择年份", // 左上角提示
          cancelText: "Cancel", // 取消按钮 文案
          confirmText: "OK", // 确认按钮 文案
          useRootNavigator: true, // 是否使用根导航器
          errorFormatText: "输入格式有误", // 输入日期 格式错误提示
          errorInvalidText: "输入年份不合法", // 输入日期 不在first 与 last 之间提示
          fieldHintText: "请输入年份", // 输入框为空时提示
          fieldLabelText: "输入正确的年份", // 输入框上方 提示
          textDirection: TextDirection.ltr, // 水平方向 显示方向 默认 ltr
        );
      }
    
      Future<DateTime?> _showDatePickerForTheme(BuildContext context) {
        return showDatePicker(
          context: context, // 上下文
          initialDate: DateTime(2022, 5, 20), // 初始化选中日期
          firstDate: DateTime(2022, 5), // 开始日期
          lastDate: DateTime(2022, 7), // 结束日期
          currentDate: DateTime.now(), // 当前日期
          initialEntryMode: DatePickerEntryMode
              .calendarOnly, // 日历弹框样式 calendar: 默认显示日历,可切换成输入模式,input:默认显示输入模式,可切换到日历,calendarOnly:只显示日历,inputOnly:只显示输入模式
          selectableDayPredicate: (dayTime) {
            // 自定义哪些日期可选
            if (dayTime == DateTime(2022, 5, 6) ||
                dayTime == DateTime(2022, 6, 8)) {
              return false;
            }
            return true;
          },
          builder: (context, child) {
            return Theme(
              data: ThemeData(
                primarySwatch: Colors.amber,
              ),
              child: child!,
            );
          },
          helpText: "请选择日期", // 左上角提示文字
          cancelText: "Cancel", // 取消按钮 文案
          confirmText: "OK", // 确认按钮 文案
          initialDatePickerMode: DatePickerMode.day, // 日期选择模式 默认为天
          useRootNavigator: true, // 是否使用根导航器
          textDirection: TextDirection.ltr, // 水平方向 显示方向 默认 ltr
        );
      }
    
      Future<TimeOfDay?> _showTimePicker(BuildContext context) {
        return showTimePicker(
          context: context, // 上下文
          initialTime: TimeOfDay.now(), // 初始化时间
          initialEntryMode: TimePickerEntryMode.input, // 时间选择模式 dial input
          useRootNavigator: true, // 是否使用根导航 默认true
          cancelText: "取消", // 取消按钮 文案
          confirmText: "确认", // 确认按钮 文案
          helpText: "请选择时间", // 左上角提示语
          errorInvalidText: "输入时间不合法", // 属于时间不合法 提示语
          hourLabelText: "小时", // 小时 提示语
          minuteLabelText: "分钟", // 分钟 提示语
          // 时间选择模式变化 回调
          onEntryModeChanged: (mode) {
            print("Mode Changed $mode");
          },
        );
      }
    }
    
    123.gif

    MSCustomDatePickerDemo

    
    class MSCustomDatePickerDemo extends StatelessWidget {
      const MSCustomDatePickerDemo({Key? key}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(title: Text("MSCustomDatePickerDemo")),
          body: Padding(
            padding: EdgeInsets.all(24),
            child: ElevatedButton(
              child: Text("CustomDatePicker"),
              onPressed: () async {
                DateTime? _dateTime = await _showCustomDatePicker(context);
                if (_dateTime == null) {
                  print("取消选择");
                } else {
                  print("选择 $_dateTime");
                }
              },
            ),
          ),
        );
      }
    
      Future<DateTime?> _showCustomDatePicker(BuildContext context) {
        return showDialog<DateTime>(
          context: context,
          builder: (context) {
            return MSCustomDatePicker(
              initialDate: DateTime.now(),
              firstDate: DateTime(2021, 10, 10),
              lastDate: DateTime(2022, 10, 10),
              helpText: "请选择日期",
            );
          },
        );
      }
    }
    
    class MSCustomDatePicker extends StatelessWidget {
      MSCustomDatePicker({
        Key? key,
        required this.initialDate,
        required this.firstDate,
        required this.lastDate,
        this.helpText,
        this.cancelText = "取消",
        this.sureText = "确定",
      });
    
      final DateTime initialDate;
      final DateTime firstDate;
      final DateTime lastDate;
      final String? helpText;
      final String cancelText;
      final String sureText;
    
      DateTime? _chooseDateTime;
    
      @override
      Widget build(BuildContext context) {
        _chooseDateTime = initialDate;
        final ValueNotifier<DateTime> _chooseDateValueNoti =
            ValueNotifier<DateTime>(initialDate);
    
        final double textScaleFactor =
            math.min(MediaQuery.of(context).textScaleFactor, 1.3);
        final Size _calendarPortraitDialogSize = Size(330.0, 518.0);
        final Size dialogSize = _calendarPortraitDialogSize * textScaleFactor;
    
        final MaterialLocalizations localizations =
            MaterialLocalizations.of(context);
    
        final header = SizedBox(
          height: 120,
          child: Material(
            color: Theme.of(context).primaryColor,
            child: Padding(
              padding: EdgeInsetsDirectional.only(start: 24, end: 12),
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  SizedBox(height: 16),
                  Text(
                    helpText ?? "",
                    textAlign: TextAlign.center,
                    style: TextStyle(color: Colors.grey[200]),
                  ),
                  const Flexible(child: SizedBox(height: 38)),
                  ValueListenableBuilder<DateTime>(
                    valueListenable: _chooseDateValueNoti,
                    builder: (context, datetime, child) {
                      final String dateText =
                          localizations.formatMediumDate(datetime);
                      return Text(
                        dateText,
                        textScaleFactor: 2.0,
                        style: TextStyle(color: Colors.white),
                      );
                    },
                  ),
                ],
              ),
            ),
          ),
        );
    
        final picker = CalendarDatePicker(
          initialDate: initialDate,
          firstDate: firstDate,
          lastDate: lastDate,
          currentDate: DateTime.now(),
          onDateChanged: (datetime) {
            _chooseDateTime = datetime;
            _chooseDateValueNoti.value = datetime;
            print("DateChanged $datetime");
          },
        );
    
        final Widget actions = Container(
          alignment: AlignmentDirectional.centerEnd,
          constraints: const BoxConstraints(minHeight: 52.0),
          padding: const EdgeInsets.symmetric(horizontal: 8),
          child: OverflowBar(
            spacing: 8,
            children: <Widget>[
              TextButton(
                onPressed: () {
                  Navigator.of(context).pop();
                },
                child: Text(cancelText),
              ),
              TextButton(
                onPressed: () {
                  Navigator.of(context).pop(_chooseDateTime);
                },
                child: Text(sureText),
              ),
            ],
          ),
        );
    
        return Dialog(
          insetPadding:
              const EdgeInsets.symmetric(horizontal: 16.0, vertical: 24.0),
          child: AnimatedContainer(
            duration: Duration(milliseconds: 150),
            height: dialogSize.height,
            width: dialogSize.width,
            curve: Curves.easeIn,
            child: Builder(
              builder: (context) {
                return Column(
                  mainAxisSize: MainAxisSize.min,
                  crossAxisAlignment: CrossAxisAlignment.stretch,
                  children: [
                    header,
                    Expanded(child: picker),
                    actions,
                  ],
                );
              },
            ),
          ),
        );
      }
    }
    
    124.gif

    相关文章

      网友评论

          本文标题:Flutter 之时间日期选择器(DatePicker,Time

          本文链接:https://www.haomeiwen.com/subject/ncqxprtx.html