Xamarin中如何实现密码输入逐字符替换为自定义掩码字符
Xamarin 表单密码输入动态掩码实现方案
实现逻辑核心:内部维护真实密码的存储变量,监听文本变更事件,仅保留最新输入的1位字符为明文,其余已输入完成的字符统一替换为指定掩码字符,输入下一位时自动将上一位明文转为掩码。
共享层实现代码
直接继承原生Entry控件做扩展,不需要额外引入第三方库:
public class DynamicMaskPasswordEntry : Entry { public static readonly BindableProperty RealPasswordProperty = BindableProperty.Create( propertyName: nameof(RealPassword), returnType: typeof(string), declaringType: typeof(DynamicMaskPasswordEntry), defaultValue: string.Empty, defaultBindingMode: BindingMode.TwoWay); /// <summary> /// 真实密码值,业务层直接绑定该属性取值 /// </summary> public string RealPassword { get => (string)GetValue(RealPasswordProperty); set => SetValue(RealPasswordProperty, value); } public static readonly BindableProperty MaskCharProperty = BindableProperty.Create( propertyName: nameof(MaskChar), returnType: typeof(char), declaringType: typeof(DynamicMaskPasswordEntry), defaultValue: '*'); /// <summary> /// 自定义掩码字符,默认使用* /// </summary> public char MaskChar { get => (char)GetValue(MaskCharProperty); set => SetValue(MaskCharProperty, value); } // 防止更新掩码文本时触发递归TextChanged事件 private bool _isRenderingMask; public DynamicMaskPasswordEntry() { // 禁用原生密码模式,避免强制全掩码 IsPassword = false; TextChanged += OnInputTextChanged; } private void OnInputTextChanged(object sender, TextChangedEventArgs e) { if (_isRenderingMask) return; // 处理删除操作:同步裁剪真实密码长度 if (e.NewTextValue.Length < (e.OldTextValue?.Length ?? 0)) { int deleteCount = e.OldTextValue.Length - e.NewTextValue.Length; if (RealPassword.Length >= deleteCount) { RealPassword = RealPassword.Substring(0, RealPassword.Length - deleteCount); } RenderMaskDisplay(); return; } // 处理新增输入:提取新输入的字符追加到真实密码 if (e.NewTextValue.Length > RealPassword.Length) { string newChars = e.NewTextValue.Substring(RealPassword.Length); RealPassword += newChars; } RenderMaskDisplay(); } private void RenderMaskDisplay() { _isRenderingMask = true; if (RealPassword.Length <= 1) { // 仅1位字符时直接显示明文 Text = RealPassword; } else { // 超过1位时,前N-1位替换为掩码,最后1位保留明文 Text = new string(MaskChar, RealPassword.Length - 1) + RealPassword[^1]; } // 光标强制定位到文本末尾,避免用户手动移动光标导致输入错位 CursorPosition = Text.Length; _isRenderingMask = false; } }
使用说明
- 不要开启Entry原生的
IsPassword="True"属性,该属性会强制所有字符显示为固定掩码,无法实现最后一位临时明文的效果 - 业务逻辑中获取密码请直接绑定
RealPassword属性,Text属性仅存储带掩码的显示内容,不能作为真实密码使用 - 自定义掩码只需要给
MaskChar属性赋值即可,比如设置为●就可以实现常见的圆点掩码效果 - 如果需要输入框失焦后隐藏最后一位明文,可以额外监听
Unfocused事件,在事件中将文本全量替换为掩码字符串即可
XAML调用示例
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:local="clr-namespace:你的项目命名空间" x:Class="你的页面类名"> <StackLayout Padding="20"> <local:DynamicMaskPasswordEntry Placeholder="请输入密码" MaskChar="*" RealPassword="{Binding LoginPassword}" FontSize="16"/> </StackLayout> </ContentPage>
实现效果完全匹配需求:输入第一个字符f时输入框显示f,输入第二个字符o时,第一位的f自动替换为*,输入框显示*o;输入第三个字符x时,第二位的o也替换为*,输入框显示**x,删除操作也会同步匹配掩码长度,不会出现错位问题。
内容的提问来源于stack exchange,提问作者Martin Schneider
相关产品推荐
相关产品推荐

