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

