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

Unity中使用TextMeshPro实现多输入框PIN登录的问题解决

多TMP Input字段PIN登录优化方案(适配新输入系统)

核心问题解决思路

  1. 键盘切换闪烁:禁用输入框失活时隐藏键盘的行为,直接切换焦点并保持键盘激活状态
  2. 新输入系统焦点失效:使用InputSystemUIInputModule替代旧UI输入模块,统一管理焦点切换
  3. 跨平台退格键处理:监听新输入系统的取消(退格)事件,实现自动回退到上一个输入框的逻辑

步骤1:配置TMP InputField属性

给每个PIN输入框设置以下属性:

  • Content Type: Integer Number
  • Character Limit: 1
  • Keyboard Type: Number Pad
  • Should Hide Keyboard On Focus Loss: 取消勾选(或通过代码设置)
  • 绑定On Value Changed事件到PIN管理脚本的对应方法

步骤2:实现PIN管理脚本

创建PINManager脚本,挂载到包含所有输入框的父物体上:

using UnityEngine;
using UnityEngine.EventSystems;
using TMPro;
using UnityEngine.InputSystem;
using System.Linq;

public class PINManager : MonoBehaviour
{
    [SerializeField] private TMP_InputField[] pinInputFields;
    private int currentInputIndex = 0;
    private InputSystemUIInputModule inputModule;

    private void Awake()
    {
        inputModule = FindObjectOfType<InputSystemUIInputModule>();
        if (inputModule == null)
        {
            Debug.LogError("场景中未找到InputSystemUIInputModule,请替换EventSystem的UI输入模块");
            return;
        }

        // 初始化第一个输入框焦点
        SetActiveInputField(0);

        // 监听退格/取消事件
        inputModule.cancel.action.performed += HandleBackspace;
    }

    private void OnDestroy()
    {
        if (inputModule != null)
        {
            inputModule.cancel.action.performed -= HandleBackspace;
        }
    }

    // 输入框内容改变时自动切换焦点
    public void OnInputValueChanged(string input)
    {
        if (!string.IsNullOrEmpty(input) && int.TryParse(input, out _))
        {
            if (currentInputIndex < pinInputFields.Length - 1)
            {
                currentInputIndex++;
                SetActiveInputField(currentInputIndex);
            }
            else
            {
                // PIN输入完成,执行验证逻辑
                ValidatePIN();
            }
        }
    }

    // 处理退格键逻辑
    private void HandleBackspace(InputAction.CallbackContext ctx)
    {
        var currentField = pinInputFields[currentInputIndex];
        if (!string.IsNullOrEmpty(currentField.text))
        {
            currentField.text = string.Empty;
        }
        else if (currentInputIndex > 0)
        {
            currentInputIndex--;
            SetActiveInputField(currentInputIndex);
            pinInputFields[currentInputIndex].text = string.Empty;
        }
    }

    // 设置当前激活的输入框
    private void SetActiveInputField(int index)
    {
        if (index < 0 || index >= pinInputFields.Length) return;

        // 确保所有输入框失活时不隐藏键盘
        foreach (var field in pinInputFields)
        {
            field.shouldHideKeyboardOnFocusLoss = false;
        }

        // 使用新输入系统的方式设置焦点
        EventSystem.current.SetSelectedGameObject(pinInputFields[index].gameObject);
        // 强制激活输入框编辑状态,保持键盘打开
        pinInputFields[index].ActivateInputField();
    }

    // PIN验证逻辑
    private void ValidatePIN()
    {
        string pin = string.Concat(pinInputFields.Select(f => f.text));
        Debug.Log($"输入的PIN:{pin}");
        // 此处添加你的PIN验证逻辑
    }
}

步骤3:场景配置

  • 替换EventSystem组件上的StandaloneInputModule为InputSystemUIInputModule(右键菜单添加:UI -> Input System UI Input Module)
  • 将四个TMP_InputField按顺序拖入PINManager的pinInputFields数组中
  • 给每个输入框的On Value Changed事件绑定PINManager的OnInputValueChanged方法,参数类型设置为String

关键注意事项

  • 所有输入框的键盘类型必须统一为数字键盘,避免切换时键盘类型变化导致闪烁
  • 如果需要隐藏PIN输入(显示为*),可设置TMP_InputField的Input Type为Password,同时保持Content Type为Integer Number
  • 测试时需在真机上验证键盘行为,编辑器中可能无法完全模拟移动端键盘状态

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 09:20:11