国内手机号一般11位数字,在登录注册等页面经常会用到,其他信息介绍页面也可能会用到手机号的显示。
场景如下图:
一、EditText输入框
使用:binding.phoneEditText.setFormatRules(3, 4, 4)
private const val TAG = 100010
/**
* Set format rules
*
* @param array format rules array, if you want to format as 'xxx xxxx xxxx', pass 3, 4, 4.
* @param formatChar format char, default is space.
*/
fun EditText.setFormatRules(vararg array: Int, formatChar: Char = ' ') {
require(array.size > 1) { "Format array size must greater than 1." }
var count = 0
//间隔字符位置索引的集合
val list = ArrayList<Int>(array.size - 1)
array.forEachIndexed { index, item ->
count += item
if (index != array.lastIndex) {
list.add(count + index)
}
}
//11位数字+2位空格
val maxLength = count + array.size - 1
//从已经移出的FormatTextWatcher获取文本
val oldText = textWithFormatRemoved
//设置新的FormatTextWatcher
setFormatTextWatcher(this, formatChar, list, maxLength)
//过滤所有的非InputFilter.LengthFilter集合
val filterList = this.filters.filter { it !is InputFilter.LengthFilter }
//追加到末尾一个InputFilter.LengthFilter
this.filters = Array(filterList.size + 1) {
if (it < filterList.size) filterList[it] else InputFilter.LengthFilter(maxLength)
}
//设置旧的文本
setText(oldText)
//光标移动到最后一个位置
setSelection(text.length)
}
/***
* Get the text with format removed.
*/
val EditText.textWithFormatRemoved: String
get() {
val watcher = getTag(TAG) as? FormatTextWatcher
return if (watcher == null) {
text.toString()
} else {
text.toString().replace(watcher.formatChar.toString(), "")
}
}
/**
* Set format edit listener.
*
* @param listener isComplete: is edit complete or not, text: text with format removed.
*/
fun EditText.setOnFormatEditListener(listener: (isComplete: Boolean, text: String) -> Unit) {
val watcher = getTag(TAG) as? FormatTextWatcher
require(watcher != null) { "You should call setFormatRules first." }
watcher.onFormatEditListener = listener
}
/**
* 设置格式化文本监听器
*
* @param et 输入框
* @param formatChar 间隔字符,比如是空格
* @param list 间隔字符位置索引的集合,比如是3,8
* @param maxLength 整个文本的长度,比如是11+2=13
*/
private fun setFormatTextWatcher(
et: EditText,
formatChar: Char,
list: List<Int>,
maxLength: Int
) {
//获取旧的FormatTextWatcher
var watcher = et.getTag(TAG) as? FormatTextWatcher
if (watcher == null) {
watcher = FormatTextWatcher(et)
et.tag = TAG
et.addTextChangedListener(watcher)
}
//间隔字符
watcher.formatChar = formatChar
//设置新的『间隔字符位置索引的集合』
watcher.formatCharIndexList.clear()
watcher.formatCharIndexList.addAll(list)
//设置文本长度
watcher.maxLength = maxLength
}
class FormatTextWatcher(private val et: EditText) : TextWatcher {
var formatChar: Char = ' '
val formatCharIndexList = ArrayList<Int>()
var maxLength = 0
var onFormatEditListener: ((isComplete: Boolean, text: String) -> Unit)? = null
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
override fun afterTextChanged(s: Editable?) {
val value = s?.toString() ?: return
if (value.isEmpty()) return
//最后一个字符是『间隔字符』
if (value.last() == formatChar) {
//删除最后一个字符
s.delete(value.lastIndex, value.lastIndex + 1)
//更新选择的位置
updateSelectionPosition(s)
return
}
//遍历文本的每一个字符
value.forEachIndexed { index, c ->
//当前索引的在『间隔字符索引集合』里面
if (formatCharIndexList.contains(index)) {
//当前字符不是『间隔字符』,就需要替换成『间隔字符』
if (c != formatChar) {
//保存原始filters
val filters = s.filters
//设置一个空数组filters
s.filters = emptyArray()
//替换成『间隔字符』
s.insert(index, formatChar.toString())
//还原filters
s.filters = filters
//更新选择的位置
updateSelectionPosition(s)
return
}
} else {
//当前字符是『间隔字符』
if (c == formatChar) {
//删除当前字符
s.delete(index, index + 1)
//更新选择的位置
updateSelectionPosition(s)
return
}
}
}
updateSelectionPosition(s)
val isComplete = value.length == maxLength
val text = value.replace(formatChar.toString(), "")
onFormatEditListener?.invoke(isComplete, text)
}
/**
* 更新选择位置
*/
private fun updateSelectionPosition(s: Editable) {
val index = et.selectionStart - 1
s.toString().getOrNull(index)?.let {
if (it == formatChar) {
et.setSelection(index)
}
}
}
/**
* 处理手机号
*/
fun EditText.dealPhoneNumber(): String {
val originAccount = text?.toString() ?: ""
return originAccount.replace(" ", "")
}
二、TextView文本字符串
/**
* 处理手机号格式按照 *** **** ****处理
*/
fun String.dealPhoneFormat(): String {
val sb = StringBuilder()
if (TextUtils.isEmpty(this)) {
return ""
}
val inputNumber: String = replace(" ", "")
var a = "" //存储第一段的三位数
var b = "" //存储第二段的四位数
var c = "" //存储第三段的四位数
if (inputNumber.length >= 3) {
a = inputNumber.substring(0, 3)
} else if (inputNumber.length < 3) {
a = inputNumber.substring(0, inputNumber.length)
}
if (inputNumber.length >= 7) {
b = inputNumber.substring(3, 7)
c = inputNumber.substring(7, inputNumber.length)
} else if (inputNumber.length in 4..6) {
b = inputNumber.substring(3, inputNumber.length)
}
if (a.isNotEmpty()) {
sb.append(a)
if (a.length == 3) {
sb.append(" ")
}
}
if (b.isNotEmpty()) {
sb.append(b)
if (b.length == 4) {
sb.append(" ")
}
}
if (c.isNotEmpty()) {
sb.append(c)
}
return sb.toString()
}
三、Textview 文本字符串*隐藏
/**
* 隐藏手机号中间的部分
*/
val String.hideMiddle: String
get() {
val split = split(" ").toMutableList()
if (split.size > 1) {
split[1] = "****"
}
return split.joinToString(separator = "")
}
/**
* 处理手机号格式按照 *** **** ****处理
*/
fun String.dealPhoneFormat(): String {
val sb = StringBuilder()
if (TextUtils.isEmpty(this)) {
return ""
}
val inputNumber: String = replace(" ", "")
var a = "" //存储第一段的三位数
var b = "" //存储第二段的四位数
var c = "" //存储第三段的四位数
if (inputNumber.length >= 3) {
a = inputNumber.substring(0, 3)
} else if (inputNumber.length < 3) {
a = inputNumber.substring(0, inputNumber.length)
}
if (inputNumber.length >= 7) {
b = inputNumber.substring(3, 7)
c = inputNumber.substring(7, inputNumber.length)
} else if (inputNumber.length in 4..6) {
b = inputNumber.substring(3, inputNumber.length)
}
if (a.isNotEmpty()) {
sb.append(a)
if (a.length == 3) {
sb.append(" ")
}
}
if (b.isNotEmpty()) {
sb.append(b)
if (b.length == 4) {
sb.append(" ")
}
}
if (c.isNotEmpty()) {
sb.append(c)
}
return sb.toString()
}