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

Flutter TextFormField输入格式化器求助:特定格式输入限制

实现符合指定格式的TextFormField输入格式化器

针对你需要的「两位字符-四位数字-两位数字-四位/五位数字」格式,我们可以自定义一个TextInputFormatter来实现,下面是完整的实现方案:

1. 自定义输入格式化器类

创建一个CustomCodeFormatter类,继承TextInputFormatter,核心逻辑在formatEditUpdate方法中处理输入内容:

class CustomCodeFormatter extends TextInputFormatter {
  @override
  TextEditingValue formatEditUpdate(
    TextEditingValue oldValue,
    TextEditingValue newValue,
  ) {
    // 移除所有分隔符,处理原始输入内容
    final cleanText = newValue.text.replaceAll('-', '');
    String formattedText = '';

    // 验证并分段处理输入
    if (cleanText.isNotEmpty) {
      // 第一段:两位英文字符
      final firstSegment = cleanText.substring(0, cleanText.length > 2 ? 2 : cleanText.length);
      // 只允许英文字符
      final validFirstSegment = firstSegment.replaceAll(RegExp(r'[^A-Za-z]'), '');
      formattedText += validFirstSegment;

      // 如果第一段长度达到2,添加分隔符并处理第二段(四位数字)
      if (validFirstSegment.length == 2 && cleanText.length > 2) {
        formattedText += '-';
        final secondSegmentStart = 2;
        final secondSegmentEnd = cleanText.length > 6 ? 6 : cleanText.length;
        final secondSegment = cleanText.substring(secondSegmentStart, secondSegmentEnd);
        // 只允许数字
        final validSecondSegment = secondSegment.replaceAll(RegExp(r'[^0-9]'), '');
        formattedText += validSecondSegment;

        // 如果第二段长度达到4,添加分隔符并处理第三段(两位数字)
        if (validSecondSegment.length == 4 && cleanText.length > 6) {
          formattedText += '-';
          final thirdSegmentStart = 6;
          final thirdSegmentEnd = cleanText.length > 8 ? 8 : cleanText.length;
          final thirdSegment = cleanText.substring(thirdSegmentStart, thirdSegmentEnd);
          final validThirdSegment = thirdSegment.replaceAll(RegExp(r'[^0-9]'), '');
          formattedText += validThirdSegment;

          // 如果第三段长度达到2,添加分隔符并处理第四段(四/五位数字)
          if (validThirdSegment.length == 2 && cleanText.length > 8) {
            formattedText += '-';
            final fourthSegment = cleanText.substring(8);
            final validFourthSegment = fourthSegment.replaceAll(RegExp(r'[^0-9]'), '');
            // 限制第四段最多5位数字
            if (validFourthSegment.length > 5) {
              formattedText += validFourthSegment.substring(0, 5);
            } else {
              formattedText += validFourthSegment;
            }
          }
        }
      }
    }

    // 计算光标位置,确保光标始终在正确位置
    int cursorPosition = newValue.selection.end;
    final separatorCount = formattedText.split('-').length - 1;
    // 光标位置需要加上自动插入的分隔符数量
    final originalCleanLength = cleanText.length;
    final formattedLength = formattedText.length;
    if (originalCleanLength > oldValue.text.replaceAll('-', '').length) {
      cursorPosition = formattedLength;
    } else {
      // 删除操作时调整光标位置
      final oldSeparatorCount = oldValue.text.split('-').length - 1;
      cursorPosition = newValue.selection.end + (separatorCount - oldSeparatorCount);
      if (cursorPosition < 0) cursorPosition = 0;
    }

    return TextEditingValue(
      text: formattedText,
      selection: TextSelection.collapsed(offset: cursorPosition),
    );
  }
}

2. 在TextFormField中使用

将自定义的格式化器添加到TextFormField的inputFormatters数组中,同时可以配合keyboardType来优化输入体验:

TextFormField(
  decoration: const InputDecoration(
    labelText: '输入编码',
    hintText: '例如:AB-2121-11-2121',
  ),
  inputFormatters: [
    CustomCodeFormatter(),
  ],
  keyboardType: TextInputType.text,
)

代码说明

  • 输入清洗:先移除所有已有的-分隔符,避免重复添加或格式混乱
  • 分段验证:每一段分别验证字符类型(前两位仅允许字母,后续仅允许数字),并限制长度
  • 自动分隔:当某一段输入达到要求长度时,自动插入-分隔符
  • 光标处理:处理输入和删除操作时的光标位置,确保光标始终处于合理位置
  • 长度限制:第四段最多允许5位数字,符合你给出的两种示例格式

这个实现会自动帮用户格式化输入,比如输入AB2121112121会自动变成AB-2121-11-2121,输入到第五位数字时会变成AB-2121-11-21214,同时会过滤掉不符合要求的字符(比如前两位输入数字会被自动忽略)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 02:05:21