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

如何在TextField中为部分字符使用obscureText和MaskTextInputFormatter?

Flutter TextField 实现部分字符遮挡 + 掩码格式化

实现思路

Flutter 默认的 obscureText 属性只能全遮或全不遮,要实现部分字符遮挡+掩码格式的效果,需要结合 MaskTextInputFormatter 自定义处理逻辑:

  1. 先用掩码格式化器保证输入的格式规范(比如固定分隔符、输入类型限制)
  2. 对用户输入的字符,按指定位置决定显示原内容还是替换为遮挡字符

具体实现

1. 添加依赖

先在 pubspec.yaml 中引入常用的掩码格式化包:

dependencies:
  mask_text_input_formatter: ^2.0.0

2. 自定义部分遮挡的掩码格式化器

创建一个自定义的 TextInputFormatter,先应用掩码格式,再替换需要遮挡的字符:

import 'package:flutter/services.dart';
import 'package:mask_text_input_formatter/mask_text_input_formatter.dart';

class PartialObscureMaskFormatter extends TextInputFormatter {
  final MaskTextInputFormatter maskFormatter;
  final List<int> visibleIndices; // 原始输入中需要显示的字符索引(从0开始)
  final String obscuringCharacter;

  PartialObscureMaskFormatter({
    required this.maskFormatter,
    required this.visibleIndices,
    this.obscuringCharacter = '•',
  });

  @override
  TextEditingValue formatEditUpdate(TextEditingValue oldValue, TextEditingValue newValue) {
    // 先应用掩码格式化规则
    final maskedResult = maskFormatter.formatEditUpdate(oldValue, newValue);
    final originalText = maskFormatter.getUnmaskedText(); // 获取用户输入的原始无格式文本
    
    final displayTextBuffer = StringBuffer();
    int originalCharIndex = 0;
    
    // 遍历掩码后的每个字符,区分固定格式符和用户输入字符
    for (int i = 0; i < maskedResult.text.length; i++) {
      final currentChar = maskedResult.text[i];
      if (maskFormatter.isMaskChar(currentChar)) {
        // 固定格式符(比如-、空格)直接保留
        displayTextBuffer.write(currentChar);
      } else {
        // 用户输入的字符,判断是否在需要显示的索引范围内
        if (visibleIndices.contains(originalCharIndex)) {
          displayTextBuffer.write(originalText[originalCharIndex]);
        } else {
          displayTextBuffer.write(obscuringCharacter);
        }
        originalCharIndex++;
      }
    }

    return TextEditingValue(
      text: displayTextBuffer.toString(),
      selection: maskedResult.selection, // 复用掩码格式化后的光标位置
      composing: maskedResult.composing,
    );
  }
}

3. 在TextField中使用

以实现「前3位显示、中间4位遮挡、后4位显示,格式为XXX-****-XXXX」为例:

import 'package:flutter/material.dart';
import 'package:mask_text_input_formatter/mask_text_input_formatter.dart';

class PartialObscureTextField extends StatelessWidget {
  PartialObscureTextField({super.key});

  // 定义掩码规则:X代表数字,-是固定分隔符
  final maskFormatter = MaskTextInputFormatter(
    mask: 'XXX-XXXX-XXXX',
    filter: {'X': RegExp(r'[0-9]')}, // 只允许输入数字
  );

  // 自定义部分遮挡格式化器:显示原始输入的第0、1、2位(前3个),第7-10位(后4个)
  final partialFormatter = PartialObscureMaskFormatter(
    maskFormatter: maskFormatter,
    visibleIndices: [0, 1, 2, 7, 8, 9, 10],
  );

  @override
  Widget build(BuildContext context) {
    return TextField(
      inputFormatters: [partialFormatter],
      obscureText: false, // 必须设为false,因为我们自己处理遮挡逻辑
      keyboardType: TextInputType.number,
      decoration: const InputDecoration(
        hintText: '请输入示例号码',
        border: OutlineInputBorder(),
      ),
    );
  }
}

关键说明

  • 区分掩码中的固定格式符和用户输入字符:只对用户输入的部分做遮挡处理,固定格式符(比如分隔符)保持原样
  • visibleIndices 是基于用户原始输入的字符索引(不含格式符),比如输入123456789012,原始索引0是1,索引7是8
  • 光标位置自动复用掩码格式化后的结果,保证输入体验正常

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 08:30:01