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

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();
  }
}
额外优化说明
  1. 将原有的日历图标也改为IconButton,确保点击图标区域也能触发日期选择器,交互更统一;
  2. 在_clearStartDate中重置selectedStartDate为当前时间,避免下次打开日期选择器时显示之前选中的日期;
  3. 添加dispose方法释放FocusNode和TextEditingController资源,避免内存泄漏。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 23:30:50