Created
October 8, 2021 11:23
-
-
Save allanolivei/6e3873680e2dd8cf59da1ea65929e847 to your computer and use it in GitHub Desktop.
Unity3d - Basic Input Number Mask
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections; | |
using System.Collections.Generic; | |
using System.Text; | |
using TMPro; | |
using UnityEngine; | |
using UnityEngine.Events; | |
[RequireComponent(typeof(TMP_InputField))] | |
public abstract class InputValidator : MonoBehaviour | |
{ | |
[Serializable] | |
public class BoolEvent : UnityEvent<bool> { }; | |
[SerializeField] | |
private TMP_Text alert; | |
[SerializeField] | |
private string alertMessage; | |
[SerializeField] | |
private UnityEvent onChange = null; | |
[SerializeField] | |
public BoolEvent onValidateChange = null; | |
protected TMP_InputField inputField; | |
private string formattedText = ""; | |
private bool valid = false; | |
public abstract bool IsValid(); | |
protected abstract bool FormatText(ref string newText, ref int caretPosition); | |
public string ToNumberString() | |
{ | |
return ConvertToNumberString(inputField.text); | |
} | |
protected virtual void Awake() | |
{ | |
inputField = GetComponent<TMP_InputField>(); | |
} | |
private void OnEnable() | |
{ | |
inputField.onValueChanged.AddListener(OnValueChanged); | |
} | |
private void OnDisable() | |
{ | |
inputField.onValueChanged.RemoveListener(OnValueChanged); | |
} | |
private void OnValueChanged(string newText) | |
{ | |
StopCoroutine("FormatTextCoroutine"); | |
StartCoroutine("FormatTextCoroutine"); | |
} | |
private IEnumerator FormatTextCoroutine() | |
{ | |
yield return null; | |
string text = inputField.text; | |
int caretPosition = inputField.caretPosition; | |
if (formattedText != text && FormatText(ref text, ref caretPosition)) | |
{ | |
formattedText = text; | |
inputField.text = text; | |
inputField.caretPosition = caretPosition; | |
onChange.Invoke(); | |
var currentValid = this.IsValid(); | |
if ( currentValid != valid ) | |
{ | |
valid = currentValid; | |
onValidateChange.Invoke(currentValid); | |
if(alert) | |
{ | |
if( valid ) | |
{ | |
alert.gameObject.SetActive(false); | |
} | |
else | |
{ | |
alert.text = alertMessage; | |
alert.gameObject.SetActive(true); | |
} | |
} | |
} | |
} | |
} | |
private string ConvertToNumberString(string value) | |
{ | |
StringBuilder number = new StringBuilder(); | |
foreach (char c in value) | |
if (char.IsDigit(c)) number.Append(c); | |
return number.ToString(); | |
} | |
} | |
[RequireComponent(typeof (TMP_InputField))] | |
public class InputValidatorMask : InputValidator | |
{ | |
[SerializeField] | |
private string[] masks = new string[]{ "(##) #### - ####", "(##) # #### - ####" }; | |
private int[] masksNumberAmount; | |
private int previousMaskLength; | |
protected override void Awake() | |
{ | |
base.Awake(); | |
int characterLimit = 0; | |
foreach( string mask in masks ) | |
characterLimit = Mathf.Max(characterLimit, mask.Length); | |
inputField.characterLimit = characterLimit; | |
//inputField.contentType = TMP_InputField.ContentType.Custom; | |
//inputField.lineType = TMP_InputField.LineType.SingleLine; | |
//inputField.keyboardType = TouchScreenKeyboardType.NumberPad; | |
//inputField.characterValidation = TMP_InputField.CharacterValidation.Digit; | |
CacheMasksNumberAmount(); | |
} | |
#if UNITY_EDITOR | |
private void OnValidate() | |
{ | |
CacheMasksNumberAmount(); | |
} | |
#endif | |
public override bool IsValid() | |
{ | |
string text = inputField.text; | |
string mask = FindMask(text); | |
// tamanho da mascara diferente | |
if( text.Length != mask.Length ) return false; | |
for( int i = 0 ; i < mask.Length ; i++ ) | |
{ | |
if ( mask[i] == '#' ) | |
{ | |
// fantando caracter numerico | |
if ( !char.IsDigit(text[i]) ) return false; | |
} | |
else | |
{ | |
// texto diferente da valores estaticos da mascara | |
if (mask[i] != text[i]) return false; | |
} | |
} | |
return true; | |
} | |
protected override bool FormatText(ref string newText, ref int caretPosition) | |
{ | |
string mask = FindMask(newText); | |
int total = Mathf.Min(mask.Length, newText.Length); | |
int maskLength = mask.Length; | |
for (int i = 0; i < total; i++) | |
{ | |
if (mask[i] == '#') | |
{ | |
if (!char.IsDigit(newText[i])) | |
{ | |
newText = newText.Remove(i, 1); | |
i--; | |
total = Mathf.Min(mask.Length, newText.Length); | |
// FIX* mudança de mascara | |
if (previousMaskLength > maskLength && i < (caretPosition - 1)) | |
caretPosition--; | |
} | |
} | |
else | |
{ | |
if (mask[i] != newText[i]) | |
{ | |
newText = newText.Insert(i, mask[i].ToString()); | |
total = Mathf.Min(mask.Length, newText.Length); | |
if (i < caretPosition) caretPosition++; | |
} | |
} | |
} | |
previousMaskLength = maskLength; | |
return true; | |
} | |
private void CacheMasksNumberAmount() | |
{ | |
masksNumberAmount = new int[masks.Length]; | |
for (int m = 0; m < masks.Length; m++) | |
masksNumberAmount[m] = GetNumberAmount(masks[m]); | |
} | |
private int GetNumberAmount( string stringNumber ) | |
{ | |
int amount = 0; | |
foreach( char c in stringNumber ) | |
if( char.IsDigit(c) || c == '#' ) amount++; | |
return amount; | |
} | |
private string FindMask( string text ) | |
{ | |
int textNumberAmount = GetNumberAmount(text); | |
int minDiff = 99999; | |
string mask = ""; | |
for( int m = 0 ; m < masksNumberAmount.Length ; m++ ) | |
{ | |
int diff = masksNumberAmount[m] - textNumberAmount; | |
if( diff >= 0 && diff < minDiff ) | |
{ | |
minDiff = diff; | |
mask = masks[m]; | |
} | |
} | |
return mask; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment