You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter:禁用DatePicker日期选择,实现Material/Cupertino风格年月选择器

同时支持Material和Cupertino风格的年月选择器解决方案

Material风格实现

Flutter原生的YearPicker和MonthPicker是基础组件,可以直接组合封装成年月选择弹窗,完全不需要依赖第三方包,还能精准控制选择逻辑:

Future<void> showMaterialYearMonthPicker(BuildContext context) async {
  DateTime? selectedDate = DateTime.now();
  
  // 先选择年份
  final selectedYear = await showDialog<DateTime>(
    context: context,
    builder: (context) => AlertDialog(
      title: const Text('选择年份'),
      content: SizedBox(
        height: 300,
        child: YearPicker(
          firstDate: DateTime(2000),
          lastDate: DateTime(2050),
          initialDate: selectedDate,
          selectedDate: selectedDate,
          onChanged: (date) => Navigator.pop(context, date),
        ),
      ),
    ),
  );
  
  if (selectedYear == null) return;
  
  // 再选择月份
  final selectedMonth = await showDialog<DateTime>(
    context: context,
    builder: (context) => AlertDialog(
      title: const Text('选择月份'),
      content: SizedBox(
        height: 300,
        child: MonthPicker(
          firstDate: DateTime(selectedYear.year),
          lastDate: DateTime(selectedYear.year),
          initialDate: DateTime(selectedYear.year, selectedDate!.month),
          selectedDate: DateTime(selectedYear.year, selectedDate.month),
          onChanged: (date) => Navigator.pop(context, date),
        ),
      ),
    ),
  );
  
  if (selectedMonth != null) {
    // 处理最终选中的年月
    print('选中结果:${selectedMonth.year}年${selectedMonth.month}月');
  }
}

Cupertino风格实现

用原生CupertinoPicker自定义年月选项,弹窗逻辑和系统风格保持一致:

Future<void> showCupertinoYearMonthPicker(BuildContext context) async {
  DateTime selectedDate = DateTime.now();
  
  await showCupertinoModalPopup(
    context: context,
    builder: (context) => Container(
      height: 320,
      color: CupertinoColors.systemBackground,
      child: Column(
        children: [
          // 顶部操作栏
          SizedBox(
            height: 50,
            child: Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: [
                CupertinoButton(
                  child: const Text('取消'),
                  onPressed: () => Navigator.pop(context),
                ),
                CupertinoButton(
                  child: const Text('确定'),
                  onPressed: () {
                    Navigator.pop(context);
                    // 处理最终选中的年月
                    print('选中结果:${selectedDate.year}年${selectedDate.month}月');
                  },
                ),
              ],
            ),
          ),
          // 年月选择器
          Expanded(
            child: Row(
              children: [
                // 年份选择器
                Expanded(
                  child: CupertinoPicker(
                    itemExtent: 50,
                    scrollController: FixedExtentScrollController(
                      initialItem: selectedDate.year - 2000,
                    ),
                    onSelectedItemChanged: (index) {
                      selectedDate = DateTime(2000 + index, selectedDate.month);
                    },
                    children: List.generate(51, (index) {
                      return Center(child: Text('${2000 + index}年'));
                    }),
                  ),
                ),
                // 月份选择器
                Expanded(
                  child: CupertinoPicker(
                    itemExtent: 50,
                    scrollController: FixedExtentScrollController(
                      initialItem: selectedDate.month - 1,
                    ),
                    onSelectedItemChanged: (index) {
                      selectedDate = DateTime(selectedDate.year, index + 1);
                    },
                    children: List.generate(12, (index) {
                      return Center(child: Text('${index + 1}月'));
                    }),
                  ),
                ),
              ],
            ),
          ),
        ],
      ),
    ),
  );
}

跨平台适配

通过Theme.of(context).platform自动判断当前平台,调用对应风格的选择器:

Future<void> showYearMonthPicker(BuildContext context) async {
  if (Theme.of(context).platform == TargetPlatform.iOS) {
    await showCupertinoYearMonthPicker(context);
  } else {
    await showMaterialYearMonthPicker(context);
  }
}

优势说明

  • 完全基于Flutter原生组件实现,无第三方依赖,避免版本兼容问题
  • 自定义程度高,可以根据需求调整弹窗样式、日期范围、选中逻辑
  • 严格遵循Material和Cupertino的设计规范,和系统风格统一

内容的提问来源于stack exchange,提问作者Laura

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 11:25:19