如何在TextField中为部分字符使用obscureText和MaskTextInputFormatter?
Flutter TextField 实现部分字符遮挡 + 掩码格式化
实现思路
Flutter 默认的 obscureText 属性只能全遮或全不遮,要实现部分字符遮挡+掩码格式的效果,需要结合 MaskTextInputFormatter 自定义处理逻辑:
- 先用掩码格式化器保证输入的格式规范(比如固定分隔符、输入类型限制)
- 对用户输入的字符,按指定位置决定显示原内容还是替换为遮挡字符
具体实现
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
相关产品推荐
相关产品推荐

