美文网首页
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