Flutter中如何让DateTimeFormField获得焦点并唤起日期选择器?
解决方案
出现这个问题的原因是默认未配置焦点属性的DateTimeFormField不会被纳入表单的焦点遍历序列,按Tab切换时就会被直接跳过。按以下步骤修改即可实现预期效果:
- 先扩展
CustomTextField组件,增加焦点控制相关参数透传给内部的TextFormField:
class CustomTextField extends StatelessWidget { const CustomTextField({ Key? key, this.labelText, this.icon, this.textInputAction, this.focusNode, this.onFieldSubmitted, }) : super(key: key); final String? labelText; final TextFieldIcon? icon; final TextInputAction? textInputAction; final FocusNode? focusNode; final void Function(String)? onFieldSubmitted; @override Widget build(BuildContext context) { return TextFormField( autovalidateMode: AutovalidateMode.onUserInteraction, focusNode: focusNode, onFieldSubmitted: onFieldSubmitted, decoration: InputDecoration( hintText: labelText, border: const OutlineInputBorder(), prefixIcon: icon, helperText: ' ', ), textInputAction: textInputAction, ); } factory CustomTextField.email({ String? errorMessage, String? labelText, FocusNode? focusNode, TextInputAction? textInputAction, void Function(String)? onFieldSubmitted, }) => CustomTextField( labelText: labelText ?? email, icon: const TextFieldIcon.email(), textInputAction: textInputAction, focusNode: focusNode, onFieldSubmitted: onFieldSubmitted, ); }
- 改造
CustomDateField组件,添加焦点监听逻辑,获焦时自动唤起日期选择器:
class CustomDateField extends StatefulWidget { const CustomDateField({ Key? key, this.labelText, this.hintText, this.focusNode, this.textInputAction, this.onFieldSubmitted, }) : super(key: key); final String? labelText; final String? hintText; final FocusNode? focusNode; final TextInputAction? textInputAction; final void Function(DateTime? value)? onFieldSubmitted; @override State<CustomDateField> createState() => _CustomDateFieldState(); } class _CustomDateFieldState extends State<CustomDateField> { DateTime? _selectedDate; @override Widget build(BuildContext context) { return Focus( onFocusChange: (hasFocus) { if (hasFocus) { // 获得焦点时自动唤起日期选择器 _showDatePicker(); } }, child: DateTimeFormField( focusNode: widget.focusNode, textInputAction: widget.textInputAction, onFieldSubmitted: (_) => widget.onFieldSubmitted?.call(_selectedDate), mode: DateTimeFieldPickerMode.date, dateFormat: DateFormat.yMd(), decoration: InputDecoration( labelText: widget.labelText, hintText: widget.hintText, border: const OutlineInputBorder(), helperText: ' ', ), onDateSelected: (date) { setState(() { _selectedDate = date; }); }, ), ); } Future<void> _showDatePicker() async { final pickedDate = await showDatePicker( context: context, initialDate: _selectedDate ?? DateTime.now(), firstDate: DateTime(1900), lastDate: DateTime.now(), ); if (pickedDate != null) { setState(() { _selectedDate = pickedDate; }); // 选完日期后自动移动焦点到下一个输入项 widget.onFieldSubmitted?.call(pickedDate); } else { // 用户取消选择时释放焦点,可按需调整逻辑 widget.focusNode?.unfocus(); } } }
- 最后在表单页面为所有字段绑定
FocusNode,明确指定焦点流转顺序:
class FormDialog extends ConsumerWidget { FormDialog({ Key? key, }) : super(key: key); // 定义每个字段的独立FocusNode final _firstNameFocus = FocusNode(); final _lastNameFocus = FocusNode(); final _dobFocus = FocusNode(); final _emailFocus = FocusNode(); @override Widget build(BuildContext context, WidgetRef ref) { return Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ const SizedBox(height: 12), CustomTextField( labelText: firstName, focusNode: _firstNameFocus, textInputAction: TextInputAction.next, onFieldSubmitted: (_) => FocusScope.of(context).requestFocus(_lastNameFocus), ), const SizedBox(height: 12), CustomTextField( labelText: lastName, focusNode: _lastNameFocus, textInputAction: TextInputAction.next, onFieldSubmitted: (_) => FocusScope.of(context).requestFocus(_dobFocus), ), const SizedBox(height: 12), CustomDateField( labelText: dateOfBirth, focusNode: _dobFocus, textInputAction: TextInputAction.next, onFieldSubmitted: (_) => FocusScope.of(context).requestFocus(_emailFocus), ), const SizedBox(height: 12), CustomTextField.email( labelText: parentEmail, focusNode: _emailFocus, textInputAction: TextInputAction.done, ), ], ); } }
按以上修改后,按Tab切换到日期字段时会自动唤起日期选择器,选择完成或取消后焦点会自动流转到下一个输入项,不会再出现跳过的问题。
内容的提问来源于stack exchange,提问作者A. Sahin
相关产品推荐
相关产品推荐

