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

Flutter实现无DatePicker的自动跳转式出生日期输入

在Flutter中实现出生日期自动跳转输入框

完全可行,核心思路是通过多个TextField组件配合FocusNode和TextEditingController,监听输入内容变化,达到指定长度时自动切换焦点到下一个输入框,同时支持删除内容时回退到上一个输入框,最终模拟出DD/MM/YYYY的输入效果。

以下是具体实现步骤和完整代码示例:

1. 初始化核心对象

创建对应日、月、年的FocusNode和TextEditingController,用于控制焦点切换和输入内容监听:

late FocusNode _dayFocusNode;
late FocusNode _monthFocusNode;
late FocusNode _yearFocusNode;
late TextEditingController _dayController;
late TextEditingController _monthController;
late TextEditingController _yearController;

@override
void initState() {
  super.initState();
  _dayFocusNode = FocusNode();
  _monthFocusNode = FocusNode();
  _yearFocusNode = FocusNode();
  _dayController = TextEditingController();
  _monthController = TextEditingController();
  _yearController = TextEditingController();

  // 监听输入变化,实现自动跳转
  _addInputListeners();
  // 初始聚焦日期输入框
  WidgetsBinding.instance.addPostFrameCallback((_) {
    FocusScope.of(context).requestFocus(_dayFocusNode);
  });
}

@override
void dispose() {
  _dayFocusNode.dispose();
  _monthFocusNode.dispose();
  _yearFocusNode.dispose();
  _dayController.dispose();
  _monthController.dispose();
  _yearController.dispose();
  super.dispose();
}

2. 实现输入监听逻辑

编写监听方法,当输入达到最大长度时自动切换焦点,删除内容为空时回退焦点:

void _addInputListeners() {
  // 日期输入框监听
  _dayController.addListener(() {
    if (_dayController.text.length == 2) {
      FocusScope.of(context).requestFocus(_monthFocusNode);
    } else if (_dayController.text.isEmpty && _monthFocusNode.hasFocus) {
      // 删除日期最后一个字符时,若当前焦点在月份,回退到日期
      FocusScope.of(context).requestFocus(_dayFocusNode);
    }
  });

  // 月份输入框监听
  _monthController.addListener(() {
    if (_monthController.text.length == 2) {
      FocusScope.of(context).requestFocus(_yearFocusNode);
    } else if (_monthController.text.isEmpty && _yearFocusNode.hasFocus) {
      FocusScope.of(context).requestFocus(_monthFocusNode);
    }
  });

  // 年份输入框监听(删除时回退到月份)
  _yearController.addListener(() {
    if (_yearController.text.isEmpty && _yearFocusNode.hasFocus) {
      FocusScope.of(context).requestFocus(_monthFocusNode);
    }
  });
}

3. 构建输入框布局

使用Row组件排列三个输入框,添加分隔符,限制输入类型和长度:

@override
Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(title: const Text("出生日期输入")),
    body: Padding(
      padding: const EdgeInsets.all(16.0),
      child: Row(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          // 日期输入框
          SizedBox(
            width: 60,
            child: TextField(
              controller: _dayController,
              focusNode: _dayFocusNode,
              keyboardType: TextInputType.number,
              inputFormatters: [
                FilteringTextInputFormatter.digitsOnly,
                LengthLimitingTextInputFormatter(2),
              ],
              decoration: const InputDecoration(
                hintText: "DD",
                border: OutlineInputBorder(),
                contentPadding: EdgeInsets.symmetric(vertical: 12, horizontal: 8),
              ),
              textAlign: TextAlign.center,
            ),
          ),
          const SizedBox(width: 8),
          const Text("/"),
          const SizedBox(width: 8),
          // 月份输入框
          SizedBox(
            width: 60,
            child: TextField(
              controller: _monthController,
              focusNode: _monthFocusNode,
              keyboardType: TextInputType.number,
              inputFormatters: [
                FilteringTextInputFormatter.digitsOnly,
                LengthLimitingTextInputFormatter(2),
              ],
              decoration: const InputDecoration(
                hintText: "MM",
                border: OutlineInputBorder(),
                contentPadding: EdgeInsets.symmetric(vertical: 12, horizontal: 8),
              ),
              textAlign: TextAlign.center,
            ),
          ),
          const SizedBox(width: 8),
          const Text("/"),
          const SizedBox(width: 8),
          // 年份输入框
          SizedBox(
            width: 100,
            child: TextField(
              controller: _yearController,
              focusNode: _yearFocusNode,
              keyboardType: TextInputType.number,
              inputFormatters: [
                FilteringTextInputFormatter.digitsOnly,
                LengthLimitingTextInputFormatter(4),
              ],
              decoration: const InputDecoration(
                hintText: "YYYY",
                border: OutlineInputBorder(),
                contentPadding: EdgeInsets.symmetric(vertical: 12, horizontal: 8),
              ),
              textAlign: TextAlign.center,
            ),
          ),
        ],
      ),
    ),
  );
}

额外优化点

  • 可以添加输入合法性验证,比如日期范围1-31,月份1-12,避免无效输入
  • 支持粘贴完整的出生日期字符串,自动拆分到对应输入框
  • 调整输入框样式,让整体更贴近原生日期输入的视觉效果

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 06:42:32