Flutter使用TextInputFormatter时如何避免输入法重启和键盘类型变更
问题根因
你遇到的输入法重启、键盘类型变更问题,本质是自定义TextInputFormatter返回新的TextEditingValue时,没有保留原newValue携带的composing属性(输入法正在组合的文本区域)。Flutter检测到组合区域被强制修改,就会触发如下日志对应的输入法重启逻辑,重启后可能出现键盘类型重置的问题:
I/TextInputPlugin(26310): Composing region changed by the framework. Restarting the input method.
此外你原有代码还有两个潜在问题:
- 仅通过新旧文本长度对比插入分隔符,仅适配正向连续输入场景,用户删除字符、在中间插入内容时分隔符逻辑会异常
- 光标固定设置为文本末尾,用户在中间修改内容时光标会跳转到末尾,使用体验差
修复后的完整代码
import 'dart:math' show min; class GroupTextFormatter extends TextInputFormatter { @override TextEditingValue formatEditUpdate( TextEditingValue oldValue, TextEditingValue newValue) { // 统一转大写,先移除所有原有分隔符避免逻辑混乱 String rawText = newValue.text.toUpperCase().replaceAll('-', ''); StringBuffer finalTextBuffer = StringBuffer(); for (int i = 0; i < rawText.length; i++) { finalTextBuffer.write(rawText[i]); // 第3、第6位后插入分隔符,避免末尾出现多余分隔符 if ((i == 2 || i == 5) && i != rawText.length - 1) { finalTextBuffer.write('-'); } } String finalText = finalTextBuffer.toString(); // 动态计算正确的光标偏移量,适配中间输入/删除场景 int baseOffset = newValue.selection.baseOffset; int offsetAdjust = 0; if (baseOffset > 3) offsetAdjust += 1; if (baseOffset > 6) offsetAdjust += 1; int finalOffset = min(baseOffset + offsetAdjust, finalText.length); // 核心修复点:保留原有composing属性,不要覆盖 return newValue.copyWith( text: finalText, selection: TextSelection.collapsed(offset: finalOffset), composing: newValue.composing, ); } }
补充优化建议
- 如果输入内容限定为字母、数字,可以搭配系统自带的
FilteringTextInputFormatter使用,过滤非法字符,避免分隔符逻辑异常 - 如果不需要支持中文等组合输入场景,也可以直接把
composing设置为TextRange.empty,同样不会触发输入法重启
内容的提问来源于stack exchange,提问作者Oniel
相关产品推荐
相关产品推荐

