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

Flutter实现TextFormField按指定间隔插入分隔符

实现带自定义分隔符和间隔的TextFormField格式化输入

原代码问题分析

你当前的实现存在两个核心问题:

  1. 插入索引计算错误:每次插入分隔符后字符串长度会增加,但循环仍基于原始无分隔符的字符串长度计算插入位置,导致后续分隔符插入偏移。
  2. 光标位置丢失:直接赋值_controller.text会强制光标跳到字符串末尾,用户在中间编辑时体验极差。

正确实现方案

通过自定义TextInputFormatter实现,这是Flutter官方推荐的输入格式化方式,能同时处理字符串格式化和光标位置维护。

1. 核心格式化函数

实现通用的字符串格式化方法,按指定间隔插入分隔符:

String formatWithSeparator(String value, String separator, int interval) {
  // 移除所有已有的分隔符,避免重复插入
  final cleanedValue = value.replaceAll(separator, '');
  if (cleanedValue.isEmpty) return '';

  final buffer = StringBuffer();
  for (int i = 0; i < cleanedValue.length; i++) {
    buffer.write(cleanedValue[i]);
    // 非最后一个字符,且当前位置是间隔的倍数(如第4个字符后插入分隔符)
    if ((i + 1) % interval == 0 && i != cleanedValue.length - 1) {
      buffer.write(separator);
    }
  }
  return buffer.toString();
}

2. 自定义TextInputFormatter

实现输入格式化器,处理输入更新时的字符串转换和光标位置调整:

class SeparatorTextInputFormatter extends TextInputFormatter {
  final String separator;
  final int interval;

  SeparatorTextInputFormatter({required this.separator, required this.interval});

  @override
  TextEditingValue formatEditUpdate(TextEditingValue oldValue, TextEditingValue newValue) {
    // 格式化新输入的内容
    final formattedText = formatWithSeparator(newValue.text, separator, interval);

    // 计算光标位置,避免光标跳转到末尾
    int cursorOffset = newValue.selection.end;
    final oldCleanedLength = oldValue.text.replaceAll(separator, '').length;
    final newCleanedLength = newValue.text.replaceAll(separator, '').length;

    if (oldCleanedLength < newCleanedLength) {
      // 用户输入字符:刚达到间隔长度时,光标位置加1(因为插入了分隔符)
      if (newCleanedLength % interval == 1 && newCleanedLength > 1) {
        cursorOffset += 1;
      }
    } else if (oldCleanedLength > newCleanedLength) {
      // 用户删除字符:删除间隔前最后一个字符时,光标位置减1(因为分隔符被移除)
      if (oldCleanedLength % interval == 0) {
        cursorOffset -= 1;
      }
    }

    // 确保光标位置不越界
    cursorOffset = cursorOffset.clamp(0, formattedText.length);

    return TextEditingValue(
      text: formattedText,
      selection: TextSelection.collapsed(offset: cursorOffset),
      composing: TextRange.empty,
    );
  }
}

3. 集成到TextFormField

在TextFormField中使用这个格式化器:

TextFormField(
  inputFormatters: [
    SeparatorTextInputFormatter(separator: '-', interval: 4),
  ],
  decoration: const InputDecoration(
    hintText: '请输入内容',
    border: OutlineInputBorder(),
  ),
)

效果验证

  • 输入1234 → 显示1234
  • 输入12345 → 自动变为1234-5,光标在5后
  • 输入12345678 → 显示1234-5678
  • 输入12345678910 → 显示1234-5678-910
  • 支持在任意位置编辑、删除,光标位置保持正确

内容的提问来源于stack exchange,提问作者Chris

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 17:07:14