Unity中使用TextMeshPro实现多输入框PIN登录的问题解决
多TMP Input字段PIN登录优化方案(适配新输入系统)
核心问题解决思路
- 键盘切换闪烁:禁用输入框失活时隐藏键盘的行为,直接切换焦点并保持键盘激活状态
- 新输入系统焦点失效:使用
InputSystemUIInputModule替代旧UI输入模块,统一管理焦点切换 - 跨平台退格键处理:监听新输入系统的取消(退格)事件,实现自动回退到上一个输入框的逻辑
步骤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
相关产品推荐
相关产品推荐

