Flutter DatePicker点击清除图标仍弹出问题求助
问题诊断
点击清除图标时,TextFormField的onTap事件会被触发(清除图标属于输入框的可点击区域),导致先弹出DatePicker,之后_clearStartDate才执行,因此出现了点击清除后先显示日期选择器,关闭选择器后输入框才清空的异常现象。
解决方案
给清除图标按钮添加FocusNode,点击时让图标优先获取焦点,阻止输入框的onTap事件触发。同时优化_clearStartDate函数,重置选中的日期状态。
修改后的完整代码
class BookingForm extends StatefulWidget { const BookingForm({Key? key}) : super(key: key); @override _BookingFormState createState() => _BookingFormState(); } class _BookingFormState extends State<BookingForm> { final _formKey = GlobalKey<FormState>(); TextEditingController _startDateTextController = TextEditingController(); DateTime selectedStartDate = DateTime.now(); bool showClear = false; final _clearIconFocusNode = FocusNode(); // 添加焦点节点 _selectStartDate(BuildContext context) async { final DateTime? newStartDate = await showDatePicker( context: context, initialDate: selectedStartDate, firstDate: DateTime(1900), lastDate: DateTime(2100), helpText: 'STARTING DATE' ); if(newStartDate != null && newStartDate != selectedStartDate) { setState(() { selectedStartDate = newStartDate; _startDateTextController.text = DateFormat.yMMMd().format(selectedStartDate); showClear = true; }); } } _clearStartDate() { setState(() { _startDateTextController.clear(); showClear = false; selectedStartDate = DateTime.now(); // 重置选中日期为当前时间 }); } @override Widget build(BuildContext context) { return Form( key: _formKey, child: Container( margin: EdgeInsets.only(left: AppDimensions.width20, right: AppDimensions.width20), padding: EdgeInsets.all(AppDimensions.height20), decoration: BoxDecoration( color: Colors.white70, borderRadius: BorderRadius.circular(AppDimensions.radius20), boxShadow: [ BoxShadow( color: Color(0xFFe8e8e8), blurRadius: 5.0, spreadRadius: 1.0, offset: Offset(2,2) ), ] ), child: Column( mainAxisAlignment: MainAxisAlignment.start, children: [ TextFormField( onTap: () => _selectStartDate(context), controller: _startDateTextController, keyboardType: TextInputType.datetime, readOnly: true, decoration: InputDecoration( suffixIcon: showClear ? IconButton( focusNode: _clearIconFocusNode, icon: Icon(Icons.clear), onPressed: () { _clearIconFocusNode.requestFocus(); // 优先获取焦点,阻止输入框onTap触发 _clearStartDate(); }, ) : IconButton( // 把日历图标也改成IconButton,点击同样触发日期选择 icon: Icon(Icons.date_range), onPressed: () => _selectStartDate(context), ), labelText: 'Start Date', labelStyle: TextStyle( fontSize: AppDimensions.font26, color: AppColors.paraColor ), ), validator: (value){ if(value!.isEmpty) { return 'Please enter a date'; } }, ), ElevatedButton( style: ElevatedButton.styleFrom( padding: EdgeInsets.only( top: AppDimensions.height10, bottom: AppDimensions.height10, left: AppDimensions.width45, right: AppDimensions.width45 ), primary: AppColors.mainColor2, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(AppDimensions.radius20) ) ), child: SmallText( text: 'Search', size: AppDimensions.font26, color: Colors.white, ), onPressed: (){ if(_formKey.currentState!.validate()) { _formKey.currentState!.save(); } } ), ], ), ), ); } @override void dispose() { _clearIconFocusNode.dispose(); // 释放焦点节点资源 _startDateTextController.dispose(); super.dispose(); } }
额外优化说明
- 将原有的日历图标也改为
IconButton,确保点击图标区域也能触发日期选择器,交互更统一; - 在
_clearStartDate中重置selectedStartDate为当前时间,避免下次打开日期选择器时显示之前选中的日期; - 添加
dispose方法释放FocusNode和TextEditingController资源,避免内存泄漏。
内容的提问来源于stack exchange,提问作者Alv
相关产品推荐
相关产品推荐

