Created
August 14, 2018 14:01
-
-
Save trfiladelfo/11ce6a670893895d4433c7e1da07929d to your computer and use it in GitHub Desktop.
Apply masks in Kotlin
This file contains 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
/** | |
* Realiza a formatação instânea na caixa de texto conforme o formato pré-definido. | |
* | |
* Forma de uso: | |
* <code> | |
* textview_phone.let { | |
* it.addTextChangedListener(Tools.MaskWatcher(Tools.MaskWatcher.Format.MOBILE_PHONE)) | |
* } | |
* </code> | |
* @param formats padrão para aplicar a máscara. | |
* @see Format | |
*/ | |
class MaskWatcher(private vararg val formats: Format) : TextWatcher { | |
/** | |
* Enumerador com alguns formatos pré-definidos, mas existe a possibilidade | |
* de criar um formato personalizado. | |
* [x] Suporte somente para máscaras compostas de caracteres 9 | |
* [x] Reconhecimento de caracteres numérico | |
* [] Reconhecimento de caracteres alfanúmerico | |
* | |
* Aviso: | |
* Lembre-se de que se usar uma máscara que conter algum caracter não previsto | |
* no input de teclado, inserir na tag digits para ser inputado na caixa de texto. | |
* Por exemplo - CPF ("999.999.999-99") | |
* <code> | |
* <EditText | |
* android:digits="0123456789.-/" | |
* android:inputType="number"/> | |
* </code> | |
* | |
* Caso não inserir os caracteres ponto, hífen e barra na tag digits, a máscara não irá | |
* funcionar, pois esses caracteres serão ignorados durante a inserção automática. | |
*/ | |
enum class Format(private val mask: String){ | |
CPF ("999.999.999-99"), | |
CNPJ("99.999.999/9999-99"), | |
MOBILE_PHONE ("(99)9-9999-9999"), | |
PHONE("(99)9999-9999"), | |
ZIPCODE("99999-999"), | |
DATETIME_SHORT("99/99/9999 99:99"), | |
DATETIME_LONG("99/99/9999 99:99:99"), | |
HOUR("99:99"), | |
DATE("99/99/9999"); | |
override fun toString(): String = mask | |
} | |
private var isRunning = false | |
private var isDeleting = false | |
private lateinit var defaultMask: Format | |
init { | |
formats.sortBy { it.toString().length } | |
defaultMask = formats.first() | |
} | |
/** | |
* @see TextWatcher.beforeTextChanged | |
*/ | |
override fun beforeTextChanged(charSequence: CharSequence, start: Int, count: Int, after: Int) { | |
isDeleting = count > after | |
} | |
/** | |
* @see TextWatcher.onTextChanged | |
*/ | |
override fun onTextChanged(charSequence: CharSequence, start: Int, before: Int, count: Int) { | |
} | |
/** | |
* @see TextWatcher.afterTextChanged | |
*/ | |
override fun afterTextChanged(editable: Editable) { | |
if (isRunning || isDeleting) { | |
return | |
} | |
isRunning = true | |
applyMask(editable) | |
isRunning = false | |
} | |
/** | |
* Aplica a máscara mais adequada no texto inserido | |
* | |
* @param editable texto inserido na caixa de texto | |
*/ | |
private fun applyMask(editable: Editable) { | |
val format = getFormat(editable, formats) | |
if (format == defaultMask) { | |
applyFormat(editable, format) | |
} else { | |
defaultMask = format | |
val text = editable.toString().replace("[^0-9]*".toRegex(), "") | |
editable.clear() | |
text.forEach { | |
editable.append(it) | |
applyFormat(editable, format) | |
} | |
} | |
} | |
/** | |
* Aplica o formato padrão selecionado no texto inserido | |
* | |
* @param editable texto inserido na caixa de texto | |
* @param format formato para aplicar no texto inserido | |
* | |
*/ | |
private fun applyFormat(editable: Editable, format: Format) { | |
val mask = format.toString() | |
val editableLength = editable.length | |
if (editableLength < mask.length) { | |
if (mask[editableLength] != '9') { | |
editable.append(mask[editableLength]) | |
} else if (mask[editableLength - 1] != '9') { | |
editable.insert(editableLength - 1, mask, editableLength - 1, editableLength) | |
} else { | |
val char = editable.last() | |
if (mask[editableLength] == '9') { | |
if (char !in '0'..'9') { | |
val limit = editable.subSequence(0, editable.length - 1) | |
editable.clear() | |
editable.append(limit) | |
} | |
} | |
} | |
} else if (editableLength > mask.length) { | |
val limit = editable.subSequence(0, mask.length) | |
editable.clear() | |
editable.append(limit) | |
} | |
} | |
/** | |
* Função para selecionar dinamicamente a máscara conforme o tamanho do texto inserido. | |
* | |
* @param editable texto inserido na caixa de texto | |
* @param formats lista de formatos possiveis para aplicar no texto inserido | |
*/ | |
private fun getFormat(editable: Editable, formats: Array<out Format>): Format { | |
var format: Format? = null //formats.first() | |
formats.sortBy { it.toString().length } | |
for (it in formats) { | |
val mask = it.toString() | |
if (editable.length <= mask.length) { | |
format = it | |
break | |
} | |
} | |
return format ?: formats.last() | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment