Flutter中readonly属性下切换TextField时键盘频繁弹收的解决求助
解决OTP输入框焦点切换时键盘闪烁问题
问题出在你用readOnly控制输入框的可编辑状态——当焦点切换时,原输入框从可编辑变为只读,系统会判定输入控件状态失效,先收起键盘,新输入框获得焦点后再重新唤起,导致键盘闪烁。
核心解决思路是让所有输入框保持可编辑状态,通过焦点控制输入行为,而非用readonly切换状态,修改后的完整代码如下:
import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; class OTPTextField extends StatefulWidget { const OTPTextField(); @override OTPTextFieldState createState() => OTPTextFieldState(); } class OTPTextFieldState extends State<OTPTextField> { final List<TextEditingController> _controllers = List.generate(6, (_) => TextEditingController()); final List<FocusNode> _focusNodes = List.generate(6, (_) => FocusNode()); FocusNode keyBoardFocus = FocusNode(); @override void initState() { super.initState(); // 监听焦点变化,确保空输入框聚焦时光标正常显示 for (int i = 0; i < _focusNodes.length; i++) { _focusNodes[i].addListener(() { if (_focusNodes[i].hasFocus && _controllers[i].text.isEmpty) { _controllers[i].text = ""; } }); } } void _onTextChanged(int index) { if (_controllers[index].text.length == 1 && index != 5) { // 输入完成后自动跳转到下一个输入框 FocusScope.of(context).requestFocus(_focusNodes[index + 1]); } } void onTextFieldTap(int index) { // 点击输入框直接聚焦目标 FocusScope.of(context).requestFocus(_focusNodes[index]); // 已有内容时选中,方便快速修改 if (_controllers[index].text.isNotEmpty) { _controllers[index].selection = TextSelection( baseOffset: 0, extentOffset: _controllers[index].text.length, ); } } @override Widget build(BuildContext context) { return Scaffold( body: RawKeyboardListener( focusNode: keyBoardFocus, onKey: (keyEvent) { if (keyEvent.logicalKey == LogicalKeyboardKey.backspace && keyEvent is RawKeyDownEvent) { // 找到当前聚焦的输入框索引 final currentIndex = _focusNodes.indexWhere((node) => node.hasFocus); if (currentIndex > 0 && _controllers[currentIndex].text.isEmpty) { // 当前输入框为空时,退格跳转到上一个并清空内容 FocusScope.of(context).requestFocus(_focusNodes[currentIndex - 1]); _controllers[currentIndex - 1].clear(); } } }, child: Center( child: Padding( padding: const EdgeInsets.symmetric(horizontal: 20), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: List.generate(6, (index) { return SizedBox( width: 45, child: TextField( maxLength: 1, autofocus: index == 0, onTap: () => onTextFieldTap(index), cursorColor: Colors.black, cursorWidth: 2, cursorRadius: const Radius.circular(5), controller: _controllers[index], focusNode: _focusNodes[index], decoration: InputDecoration( border: OutlineInputBorder( borderRadius: BorderRadius.circular(5), ), counterText: "", // 隐藏输入长度提示 focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(5), borderSide: const BorderSide(color: Colors.blue, width: 2), ), ), inputFormatters: [FilteringTextInputFormatter.digitsOnly], keyboardType: TextInputType.number, textInputAction: index == 5 ? TextInputAction.done : TextInputAction.next, onChanged: (value) => _onTextChanged(index), // 非聚焦时禁止选中编辑,仅保留点击跳转功能 enableInteractiveSelection: _focusNodes[index].hasFocus, ), ); }), ), ), ), ), ); } @override void dispose() { // 清理资源,避免内存泄漏 for (var controller in _controllers) { controller.dispose(); } for (var node in _focusNodes) { node.dispose(); } keyBoardFocus.dispose(); super.dispose(); } }
关键修改说明:
- 移除
readOnly属性:所有输入框保持可编辑状态,彻底避免状态切换导致的键盘波动 - 用
enableInteractiveSelection控制编辑权限:非聚焦输入框禁止选中和编辑,但依然支持点击跳转焦点 - 基于焦点节点判断状态:不再维护
_isActive数组,直接通过focusNode.hasFocus判断当前活跃输入框,减少状态同步问题 - 优化焦点跳转逻辑:输入完成自动跳转到下一个,点击输入框直接聚焦目标,退格时处理空输入框的跳转逻辑
- 添加资源清理:新增
dispose方法清理控制器和焦点节点,避免内存泄漏
内容的提问来源于stack exchange,提问作者Sai kiran
相关产品推荐
相关产品推荐

