278 lines
7.4 KiB
C#
278 lines
7.4 KiB
C#
using System;
|
||
using UnityEngine;
|
||
using UnityEngine.UI;
|
||
|
||
namespace Kill.UI.Components
|
||
{
|
||
/// <summary>
|
||
/// 验证码输入组件
|
||
/// 使用方式:
|
||
/// 1. 在场景中创建一个空物体,挂载此脚本
|
||
/// 2. 创建n个Text作为验证码显示位
|
||
/// 3. 创建一个InputField作为隐藏输入框(可设置为透明或移出屏幕外)
|
||
/// 4. 在Inspector中配置digitTexts和inputField
|
||
/// </summary>
|
||
public class VerificationCodeInput : MonoBehaviour
|
||
{
|
||
[Header("验证码配置")]
|
||
[Tooltip("验证码位数")]
|
||
[Range(1, 10)]
|
||
public int codeLength = 6;
|
||
|
||
[Tooltip("是否自动验证 - 输入完成后自动触发OnCodeCompleted事件")]
|
||
public bool autoSubmit = true;
|
||
|
||
[Tooltip("是否只允许数字")]
|
||
public bool numericOnly = true;
|
||
|
||
[Header("UI引用")]
|
||
[Tooltip("验证码显示文本数组,按顺序从左到右")]
|
||
public Text[] digitTexts;
|
||
|
||
[Tooltip("隐藏的输入框(用于接收用户输入)")]
|
||
public InputField inputField;
|
||
|
||
[Header("样式配置")]
|
||
[Tooltip("未输入时的占位字符")]
|
||
public string placeholderChar = "-";
|
||
|
||
[Tooltip("输入完成后的字符(如需要隐藏可设为*)")]
|
||
public string displayChar = "";
|
||
|
||
public event Action<string> OnCodeCompleted;
|
||
public event Action<string> OnCodeChanged;
|
||
|
||
private string currentCode = "";
|
||
|
||
private void Awake()
|
||
{
|
||
Initialize();
|
||
}
|
||
|
||
private void OnEnable()
|
||
{
|
||
if (inputField != null)
|
||
{
|
||
inputField.onValueChanged.AddListener(HandleInputChanged);
|
||
inputField.onEndEdit.AddListener(HandleEndEdit);
|
||
}
|
||
}
|
||
|
||
private void OnDisable()
|
||
{
|
||
if (inputField != null)
|
||
{
|
||
inputField.onValueChanged.RemoveListener(HandleInputChanged);
|
||
inputField.onEndEdit.RemoveListener(HandleEndEdit);
|
||
}
|
||
}
|
||
|
||
private void Start()
|
||
{
|
||
RefreshDisplay();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 初始化组件
|
||
/// </summary>
|
||
private void Initialize()
|
||
{
|
||
if (inputField == null)
|
||
{
|
||
inputField = GetComponentInChildren<InputField>();
|
||
}
|
||
|
||
if (digitTexts == null || digitTexts.Length == 0)
|
||
{
|
||
digitTexts = GetComponentsInChildren<Text>();
|
||
}
|
||
|
||
if (digitTexts != null && digitTexts.Length > 0)
|
||
{
|
||
codeLength = Mathf.Min(codeLength, digitTexts.Length);
|
||
}
|
||
|
||
if (inputField != null)
|
||
{
|
||
inputField.characterLimit = codeLength;
|
||
inputField.contentType = numericOnly
|
||
? InputField.ContentType.IntegerNumber
|
||
: InputField.ContentType.Alphanumeric;
|
||
|
||
var inputText = inputField.textComponent;
|
||
if (inputText != null)
|
||
{
|
||
inputText.color = new Color(1, 1, 1, 0);
|
||
}
|
||
|
||
if (inputField.placeholder != null)
|
||
{
|
||
var placeholder = inputField.placeholder.GetComponent<Text>();
|
||
if (placeholder != null)
|
||
{
|
||
placeholder.color = new Color(1, 1, 1, 0);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 处理输入变化
|
||
/// </summary>
|
||
private void HandleInputChanged(string value)
|
||
{
|
||
if (numericOnly)
|
||
{
|
||
value = FilterNumeric(value);
|
||
if (inputField != null && inputField.text != value)
|
||
{
|
||
inputField.text = value;
|
||
return;
|
||
}
|
||
}
|
||
|
||
if (value.Length > codeLength)
|
||
{
|
||
value = value.Substring(0, codeLength);
|
||
if (inputField != null)
|
||
{
|
||
inputField.text = value;
|
||
return;
|
||
}
|
||
}
|
||
|
||
currentCode = value;
|
||
RefreshDisplay();
|
||
|
||
OnCodeChanged?.Invoke(currentCode);
|
||
|
||
if (autoSubmit && currentCode.Length == codeLength)
|
||
{
|
||
Debug.Log("自动提交");
|
||
OnCodeCompleted?.Invoke(currentCode);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 处理结束编辑(用户按下回车或失去焦点)
|
||
/// </summary>
|
||
private void HandleEndEdit(string value)
|
||
{
|
||
if (!autoSubmit && currentCode.Length == codeLength)
|
||
{
|
||
OnCodeCompleted?.Invoke(currentCode);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 刷新显示
|
||
/// </summary>
|
||
private void RefreshDisplay()
|
||
{
|
||
if (digitTexts == null) return;
|
||
|
||
for (int i = 0; i < digitTexts.Length; i++)
|
||
{
|
||
if (digitTexts[i] == null) continue;
|
||
|
||
if (i < currentCode.Length)
|
||
{
|
||
char c = currentCode[i];
|
||
digitTexts[i].text = string.IsNullOrEmpty(displayChar) ? c.ToString() : displayChar;
|
||
}
|
||
else
|
||
{
|
||
digitTexts[i].text = placeholderChar;
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 过滤非数字字符
|
||
/// </summary>
|
||
private string FilterNumeric(string input)
|
||
{
|
||
var result = "";
|
||
foreach (char c in input)
|
||
{
|
||
if (char.IsDigit(c))
|
||
{
|
||
result += c;
|
||
}
|
||
}
|
||
return result;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取当前验证码
|
||
/// </summary>
|
||
public string GetCode()
|
||
{
|
||
return currentCode;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 设置验证码(用于自动填充等)
|
||
/// </summary>
|
||
public void SetCode(string code)
|
||
{
|
||
if (code == null)
|
||
{
|
||
code = "";
|
||
}
|
||
|
||
if (code.Length > codeLength)
|
||
{
|
||
code = code.Substring(0, codeLength);
|
||
}
|
||
|
||
currentCode = code;
|
||
|
||
if (inputField != null)
|
||
{
|
||
inputField.text = currentCode;
|
||
}
|
||
|
||
RefreshDisplay();
|
||
OnCodeChanged?.Invoke(currentCode);
|
||
|
||
if (currentCode.Length == codeLength)
|
||
{
|
||
OnCodeCompleted?.Invoke(currentCode);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 清空输入
|
||
/// </summary>
|
||
public void Clear()
|
||
{
|
||
currentCode = "";
|
||
if (inputField != null)
|
||
{
|
||
inputField.text = "";
|
||
}
|
||
RefreshDisplay();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 让输入框获得焦点
|
||
/// </summary>
|
||
public void Focus()
|
||
{
|
||
if (inputField != null)
|
||
{
|
||
inputField.ActivateInputField();
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 检查验证码是否输入完整
|
||
/// </summary>
|
||
public bool IsComplete()
|
||
{
|
||
return currentCode.Length == codeLength;
|
||
}
|
||
}
|
||
}
|