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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 07:51:24