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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 15:15:05