Skip to content

Instantly share code, notes, and snippets.

@allanolivei
Created October 8, 2021 11:23
Show Gist options
  • Save allanolivei/6e3873680e2dd8cf59da1ea65929e847 to your computer and use it in GitHub Desktop.
Save allanolivei/6e3873680e2dd8cf59da1ea65929e847 to your computer and use it in GitHub Desktop.
Unity3d - Basic Input Number Mask
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