Flutter中日期范围选择器(DateRange Picker)的设计实现方法
在Flutter中实现日期范围选择器的几种方法
1. 使用Flutter官方原生组件showDateRangePicker
Flutter SDK自带日期范围选择弹窗,无需额外依赖,适合快速实现基础需求。
示例代码:
import 'package:flutter/material.dart'; class DateRangePickerDemo extends StatefulWidget { const DateRangePickerDemo({super.key}); @override State<DateRangePickerDemo> createState() => _DateRangePickerDemoState(); } class _DateRangePickerDemoState extends State<DateRangePickerDemo> { DateTimeRange? _selectedDateRange; Future<void> _showDateRangePicker() async { final picked = await showDateRangePicker( context: context, firstDate: DateTime(2020), lastDate: DateTime(2025), initialDateRange: _selectedDateRange, builder: (context, child) { return Theme( data: ThemeData.light().copyWith( colorScheme: const ColorScheme.light( primary: Colors.blue, // 选中日期的主题色 onPrimary: Colors.white, surface: Colors.white, onSurface: Colors.black, ), dialogBackgroundColor: Colors.white, ), child: child!, ); }, ); if (picked != null) { setState(() { _selectedDateRange = picked; }); } } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('日期范围选择器')), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text(_selectedDateRange == null ? '未选择日期范围' : '选中范围: ${_selectedDateRange!.start.toString().split(' ')[0]} 至 ${_selectedDateRange!.end.toString().split(' ')[0]}'), const SizedBox(height: 20), ElevatedButton( onPressed: _showDateRangePicker, child: const Text('选择日期范围'), ), ], ), ), ); } }
2. 自定义日期范围选择器(适配参考样式)
如果需要更贴合参考图的嵌入式双日期选择UI,可以手动组合组件实现:
示例代码:
import 'package:flutter/material.dart'; class CustomDateRangePicker extends StatefulWidget { const CustomDateRangePicker({super.key}); @override State<CustomDateRangePicker> createState() => _CustomDateRangePickerState(); } class _CustomDateRangePickerState extends State<CustomDateRangePicker> { DateTime? _startDate; DateTime? _endDate; Future<void> _pickDate(bool isStart) async { final picked = await showDatePicker( context: context, initialDate: isStart ? (_startDate ?? DateTime.now()) : (_endDate ?? DateTime.now()), firstDate: DateTime(2020), lastDate: DateTime(2025), ); if (picked != null) { setState(() { if (isStart) { _startDate = picked; // 自动修正结束日期不早于开始日期 if (_endDate != null && _endDate!.isBefore(picked)) { _endDate = picked; } } else { _endDate = picked; } }); } } @override Widget build(BuildContext context) { return Padding( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 20), child: Row( children: [ Expanded( child: GestureDetector( onTap: () => _pickDate(true), child: Container( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 14), decoration: BoxDecoration( border: Border.all(color: Colors.grey.shade300), borderRadius: BorderRadius.circular(8), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text('开始日期', style: TextStyle(fontSize: 12, color: Colors.grey)), const SizedBox(height: 4), Text( _startDate == null ? '选择日期' : _startDate!.toString().split(' ')[0], style: const TextStyle(fontSize: 16), ), ], ), ), ), ), const SizedBox(width: 16), const Text('至', style: TextStyle(fontSize: 16)), const SizedBox(width: 16), Expanded( child: GestureDetector( onTap: () => _pickDate(false), child: Container( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 14), decoration: BoxDecoration( border: Border.all(color: Colors.grey.shade300), borderRadius: BorderRadius.circular(8), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text('结束日期', style: TextStyle(fontSize: 12, color: Colors.grey)), const SizedBox(height: 4), Text( _endDate == null ? '选择日期' : _endDate!.toString().split(' ')[0], style: const TextStyle(fontSize: 16), ), ], ), ), ), ), ], ), ); } }
3. 使用第三方包flutter_date_pickers
如果需要更丰富的样式(如周/月选择、自定义高亮),可以使用flutter_date_pickers包,UI风格更贴近商用产品。
步骤1:添加依赖
在pubspec.yaml中加入:
dependencies: flutter_date_pickers: ^2.0.0
步骤2:实现代码
import 'package:flutter/material.dart'; import 'package:flutter_date_pickers/flutter_date_pickers.dart' as pickers; class ThirdPartyDateRangePicker extends StatefulWidget { const ThirdPartyDateRangePicker({super.key}); @override State<ThirdPartyDateRangePicker> createState() => _ThirdPartyDateRangePickerState(); } class _ThirdPartyDateRangePickerState extends State<ThirdPartyDateRangePicker> { DateTimeRange? _selectedRange; final DateTime _firstDate = DateTime(2020); final DateTime _lastDate = DateTime(2025); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('第三方日期范围选择器')), body: Column( children: [ pickers.DateRangePicker( selectedDateRange: _selectedRange, onChanged: (range) => setState(() => _selectedRange = range), firstDate: _firstDate, lastDate: _lastDate, datePickerStyles: const pickers.DatePickerStyles( selectedDateStyle: TextStyle(color: Colors.white), selectedSingleDateDecoration: BoxDecoration( color: Colors.blue, borderRadius: BorderRadius.all(Radius.circular(8)), ), ), ), const SizedBox(height: 20), Text(_selectedRange == null ? '未选择范围' : '选中: ${_selectedRange!.start.toString().split(' ')[0]} 至 ${_selectedRange!.end.toString().split(' ')[0]}'), ], ), ); } }
注意事项:
- 使用第三方包时,建议查看最新版本文档,避免版本兼容问题。
- 自定义样式可通过
Theme或组件自带参数调整颜色、字体,匹配App设计风格。
内容的提问来源于stack exchange,提问作者Himani Upadhyay
相关产品推荐
相关产品推荐

