在Android开发中,格式化输入框输入的手机号码是一个很常用的事情,比如输入13333333333,最终需要格式化成为133 3333 3333格式。这是一个很常见的需求,但是实现起来还是有点麻烦,主要体现在以下几个地方:
这里先介绍一下一个很重要的接口,TextWatcher
TextWatcher里面有三个方法:
beforeTextChanged(CharSequence s, int start, int count, int after)
onTextChanged(CharSequence s, int start, int before, int count)
afterTextChanged(Editable s)
这里有几个比较抽象的参数:beforeTextChanged的几个参数的意义分别是:
这个会比较抽象,我们可以在代码中打印一下:
et.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
Log.i("edittext", "beforeTextChanged CharSequence:(" + s + "); start: (" + start + "); count: (" + count + "); after: (" + after + ")");
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
Log.i("edittext", "onTextChanged CharSequence:(" + s + "); start: (" + start + "); before: (" + before + "); count: (" + count + ")");
}
@Override
public void afterTextChanged(Editable s) {
Log.i("edittext", "分割线---------------------------------------------------------------------------------------------\n");
}
});
我们看下打印下来的日志:
我们在第七个字符的位置输入了3个m,所以应该是有三个流程打印出来的。
我们删除了中间的三个mmm,看下日志,start = 6, count = 3, after = 0;从第六个字符开始后的3个字符被替换成了0个字符,所以是删除了三个字符,验证了我们的结论。
大家有兴趣可以自己再去验证一下粘贴复制这种情况,这里不再做论证。
简单介绍了下这几个参数的意义,下面我们分析一下上面说到的需求,格式化手机号:
当我们输入手机号的时候需要自动添加空格,而当我们删除手机号的时候也需要自动删除空格,我们可以根据beforeTextChanged()的参数方法判断出来当前是出于新增还是删除的情况:
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
if (s.length() == count && start == 0 && count != 0) {
inputMode = MODE_SET_TEXT;
} else if (after == 0) {
inputMode = MODE_DELETE;
curIndex = start;
if ((curIndex == 4 && s.length() >= 4) || (curIndex == 9 && s.length() >= 9)){
curIndex -= 1;
}
} else {
inputMode = MODE_INSERT;
curIndex = after + start;
if ((curIndex == 4 && s.length() >= 4) || (curIndex == 9 && s.length() >= 9)){
curIndex += 1;
}
}
}
这里需要注意,除了新增和删除,还有可能调用到setText()这个方法,当我们手动修改完text的时候需要通过setText()设置进去,这个时候需要一些特殊处理(当然也可以通过修改Editable参数修改)。curIndex参数用来记录当前光标所在的位置,这样可以使用户进行输入和删除包括复制粘贴的时候让光标停留在自己想要的位置,毕竟提高用户体验是我们的必要操作。
具体的代码贴在下面,大家感兴趣可以看看:
public class PhoneNumberTextWatcher implements TextWatcher {
private static final int MODE_INSERT = 0;
private static final int MODE_DELETE = 1;
private static final int MODE_SET_TEXT = 2;
/**
* 当前的输入模式,默认
*/
private int inputMode;
/**
* 当前的光标所在位置
*/
private int curIndex;
/**
* 输入手机号码的editText
*/
private EditText etPhone;
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
if (s.length() == count && start == 0 && count != 0) {
inputMode = MODE_SET_TEXT;
if (curIndex == 4 && after > 4 || (curIndex == 9 && after > 9)){
curIndex += 1;
}
} else if (after == 0) {
inputMode = MODE_DELETE;
curIndex = start;
if ((curIndex == 4 && s.length() >= 4) || (curIndex == 9 && s.length() >= 9)){
curIndex -= 1;
}
} else {
inputMode = MODE_INSERT;
curIndex = after + start;
if ((curIndex == 4 && s.length() >= 4) || (curIndex == 9 && s.length() >= 9)){
curIndex += 1;
}
}
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
String curString = s.toString();
String realString = curString.replace(" ", "");
int length = realString.length();
StringBuilder sb = new StringBuilder();
if (inputMode == MODE_INSERT) {
if (length < 3) {
return;
}
sb.append(realString.substring(0, 3));
sb.append(" ");
if (length < 7) {
sb.append(realString.substring(3, length));
} else {
sb.append(realString.substring(3, 7));
sb.append(" ");
sb.append(realString.substring(7, length));
}
} else if (inputMode == MODE_DELETE) {
if (length <= 3) {
sb.append(realString);
} else if (length <= 7) {
sb.append(realString.substring(0, 3));
sb.append(" ");
sb.append(realString.substring(3, length));
} else {
sb.append(realString.substring(0, 3));
sb.append(" ");
sb.append(realString.substring(3, 7));
sb.append(" ");
sb.append(realString.substring(7, length));
}
}
if (sb.length() != 0 && !sb.toString().equals(curString)) {
if (etPhone != null) {
etPhone.setText(sb);
}
}
if (length != 0 && etPhone != null) {
etPhone.setSelection(curIndex);
}
}
public void setEditText(EditText etPhone){
this.etPhone = etPhone;
this.etPhone.addTextChangedListener(this);
}
}
我们看下最终的效果:
使用方式:
EditText et = findViewById(R.id.et);
new PhoneNumberTextWatcher().setEditText(et);
对于银行卡号或者身份证的格式化同理也是这种思路。