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
相关产品推荐
相关产品推荐

