DatePicker

选择日期和时间的组件

DatePicker(日期选择器)是Flutter中用于选择日期和时间的内置组件,基于Material Design风格。它通过弹窗或内嵌式界面,帮助用户快速输入日期,支持年、月、日及时间的选择。核心逻 辑是通过showDatePickershowTimePicker函数触发对话框,并返回用户选择的DateTime对象。

使用场景

  • 用户注册或表单填写(如生日、预约日期)。
  • 日历类应用(如日程安排、提醒功能)。
  • 数据筛选(如选择查询时间范围)。

示例

基础日期选择

import 'package:flutter/material.dart';

class BasicDatePicker extends StatefulWidget {
  
  _BasicDatePickerState createState() => _BasicDatePickerState();
}

class _BasicDatePickerState extends State<BasicDatePicker> {
  DateTime? _selectedDate;

  Future<void> _selectDate() async {
    final DateTime? picked = await showDatePicker(
      context: context,
      initialDate: DateTime.now(),
      firstDate: DateTime(2000),
      lastDate: DateTime(2030),
    );
    if (picked != null && picked != _selectedDate) {
      setState(() {
        _selectedDate = picked;
      });
    }
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text(_selectedDate == null
                ? '未选择日期'
                : '选中日期: ${_selectedDate!.toString().split(' ')[0]}'),
            ElevatedButton(
              onPressed: _selectDate,
              child: Text('选择日期'),
            ),
          ],
        ),
      ),
    );
  }
}

时间选择和日期结合

Future<void> _selectDateTime() async {
  // 先选择日期
  DateTime? date = await showDatePicker(
    context: context,
    initialDate: DateTime.now(),
    firstDate: DateTime.now(),
    lastDate: DateTime(2025),
  );
  if (date != null) {
    // 再选择时间
    TimeOfDay? time = await showTimePicker(
      context: context,
      initialTime: TimeOfDay.now(),
    );
    if (time != null) {
      setState(() {
        _selectedDate = DateTime(
          date.year,
          date.month,
          date.day,
          time.hour,
          time.minute,
        );
      });
    }
  }
}

自定义主题与本地化

Future<void> _selectDateWithTheme() async {
  final DateTime? picked = await showDatePicker(
    context: context,
    initialDate: DateTime.now(),
    firstDate: DateTime(2020),
    lastDate: DateTime(2025),
    builder: (context, child) {
      return Theme(
        data: ThemeData.light().copyWith(
          primaryColor: Colors.orange, // 主色调
          colorScheme: ColorScheme.light(primary: Colors.orange),
          buttonTheme: ButtonThemeData(textTheme: ButtonTextTheme.primary),
        ),
        child: child!,
      );
    },
  );
  // 处理选择结果...
}

注意点

常见问题

  • 性能瓶颈: 在频繁触发的场景(如列表项中嵌套DatePicker)可能引起卡顿,建议通过StatefulWidget隔离状态。
  • 兼容性警告:
    • 在iOS设备上需依赖Cupertino风格的日期选择器(需单独导入cupertino_icons)。
    • 部分旧版本Flutter中firstDate/lastDate范围过大可能导致渲染异常。

优化技巧

  • 使用initialDate预设合理默认值,减少用户操作步骤。
  • 通过builder参数自定义主题,确保与App设计风格一致。

最佳实践

  • 始终校验返回的DateTime是否为null(用户可能取消选择)。
  • 对于国际化需求,使用MaterialLocalizations.delegate支持多语言。

构造函数

Future<DateTime?> showDatePicker({
  required BuildContext context,
  required DateTime initialDate,      // 初始显示日期
  required DateTime firstDate,        // 可选最早日期
  required DateTime lastDate,         // 可选最晚日期
  DatePickerEntryMode initialEntryMode = DatePickerEntryMode.calendar, // 初始模式(日历或输入框)
  SelectableDayPredicate? selectableDayPredicate, // 自定义日期可用性校验
  String? helpText,                   // 对话框标题文本
  CancelText? cancelText,             // 取消按钮文本
  ConfirmText? confirmText,           // 确认按钮文本
  Locale? locale,                     // 本地化设置
  bool useRootNavigator = true,       // 导航器行为
  RouteSettings? routeSettings,
  TextDirection? textDirection,
  TransitionBuilder? builder,         // 自定义UI主题
})

属性

属性名属性类型说明
initialDateDateTime弹窗初始显示的日期,通常设为当前日期或表单预设值。
firstDateDateTime用户可选择的最早日期,禁止选择此日期之前的日期。
lastDateDateTime用户可选择的最晚日期,禁止选择此日期之后的日期。
initialEntryModeDatePickerEntryMode初始界面模式,默认为日历(calendar),可选输入框(input)。
selectableDayPredicateSelectableDayPredicate回调函数,用于禁用特定日期(如周末返回false则不可选)。

关键属性解析:

  • firstDate/lastDate: 必须合理设置范围,避免用户选择无效日期(如过去日期用于未来预约)。
  • selectableDayPredicate: 可通过此属性实现业务逻辑限制(如仅允许选择工作日)。示例:
selectableDayPredicate: (DateTime day) {
  // 禁用周末
  return day.weekday != DateTime.saturday && day.weekday != DateTime.sunday;
},