终于要写博客了,以前总觉得技术大牛才能写博客,后面想想,分享个人想法与技术探讨也是一种不错的交流方式。今天讲讲我在项目中遇到的一个实际需求,也许很多人也遇到过:
EditText要求限制输入数字和英文,但是最好默认弹出数字键盘。
我也上网搜过很多种方式,将自己的总结经验带给大家参考:
android:digits="0123456789abcdefghigklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
结果:可以实现限制输入数字和英文的效果,但是默认弹出的全键盘而不是数字键盘。
tvPassword.addTextChangedListener(new TextWatcher() {
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void afterTextChanged(Editable edt) {
try {
String temp = edt.toString();
String tem = temp.substring(temp.length() - 1, temp.length());
char[] temC = tem.toCharArray();
int mid = temC[0];
if (mid >= 48 && mid <= 57) {//数字
return;
}
if (mid >= 65 && mid <= 90) {//大写字母
return;
}
if (mid > 97 && mid <= 122) {//小写字母
return;
}
edt.delete(temp.length() - 1, temp.length());
} catch (Exception e) {
e.printStackTrace();
}
}
});
结果:如果客户只输入数字或英文或中文的情况下是奏效的,但是如果在中文键盘下同时输入汉字与英文(比如:是非得失vvvv),这时候汉字也会显示出来,达不到效果,而且也是全键盘。
以上两种方式都是默认全键盘,那么有些朋友就会说,不是可以设置InputType吗?
设置InputType确实可以实现默认弹出数字键盘,但是你也会发现:刚刚已经设置好的digits或者监听来限制输入数字和英文的,现在变成只能输入数字了!!!
通过TextView源码,发现了源码里面设置digits是这样的:
//TextView构造方法
……
case com.android.internal.R.styleable.TextView_digits:
digits = a.getText(attr);
break;
……
else if (digits != null) {
createEditorIfNeeded();
mEditor.mKeyListener = DigitsKeyListener.getInstance(digits.toString());
// If no input type was specified, we will default to generic
// text, since we can't tell the IME about the set of digits
// that was selected.
mEditor.mInputType = inputType != EditorInfo.TYPE_NULL
? inputType : EditorInfo.TYPE_CLASS_TEXT;
}
……
从上面可以看出,系统在拿到xml里面设置的digits之后做了这样的操作:
mEditor.mKeyListener = DigitsKeyListener.getInstance(digits.toString());
这个就是创建了一个DigitsKeyListener,并赋值给TextView的mKeyListener ;那么我们也可以为EditText手动设置KeyListener:
String digists = "0123456789abcdefghigklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
tvPassword.setKeyListener(DigitsKeyListener.getInstance(digists));
结果:默认弹出数字键盘,限制输入数字和英文效果实现。
到了这里大家有没有觉得奇怪,为什么xml里面设置digits默认弹出的是全键盘,而代码设置却默认弹出的是数字键盘?源码里面不也是这样设置的吗?
其实决定弹出什么键盘是由InputType决定的,上面源码里面设置DigitsKeyListener.getInstance(digists)之后设置了InputType为EditorInfo.TYPE_CLASS_TEXT;这表示键盘是输入字符的,而DigitsKeyListener.getInstance源码里面已经设置了InputType
//TextView调用的getInstance
public static DigitsKeyListener getInstance(String accepted) {
// TODO: do we need a cache of these to avoid allocating?
DigitsKeyListener dim = new DigitsKeyListener();
dim.mAccepted = new char[accepted.length()];
accepted.getChars(0, accepted.length(), dim.mAccepted, 0);
return dim;
}
public DigitsKeyListener() {
this(false, false);
}
/**
* Allocates a DigitsKeyListener that accepts the digits 0 through 9,
* plus the minus sign (only at the beginning) and/or decimal point
* (only one per field) if specified.
*/
public DigitsKeyListener(boolean sign, boolean decimal) {
mSign = sign;
mDecimal = decimal;
int kind = (sign ? SIGN : 0) | (decimal ? DECIMAL : 0);
mAccepted = CHARACTERS[kind];
}
public int getInputType() {
//因为构造方法传入的mSign和mDecimal都是false,所以返回的是InputType.TYPE_CLASS_NUMBER
int contentType = InputType.TYPE_CLASS_NUMBER;
if (mSign) {
contentType |= InputType.TYPE_NUMBER_FLAG_SIGNED;
}
if (mDecimal) {
contentType |= InputType.TYPE_NUMBER_FLAG_DECIMAL;
}
return contentType;
}
由此看出DigitsKeyListener返回的InputType是InputType.TYPE_CLASS_NUMBER,而TextView并没有使用DigitsKeyListener的InputType,而是自己设置了EditorInfo.TYPE_CLASS_TEXT;故弹出的是全键盘。
我们用代码设置的setKeyListener的源码是这样的
public void setKeyListener(KeyListener input) {
setKeyListenerOnly(input);
fixFocusableAndClickableSettings();
if (input != null) {
createEditorIfNeeded();
try {
mEditor.mInputType = mEditor.mKeyListener.getInputType();
} catch (IncompatibleClassChangeError e) {
mEditor.mInputType = EditorInfo.TYPE_CLASS_TEXT;
}
// Change inputType, without affecting transformation.
// No need to applySingleLine since mSingleLine is unchanged.
setInputTypeSingleLine(mSingleLine);
} else {
if (mEditor != null) mEditor.mInputType = EditorInfo.TYPE_NULL;
}
InputMethodManager imm = InputMethodManager.peekInstance();
if (imm != null) imm.restartInput(this);
}
这里的:
InputMethodManager imm = InputMethodManager.peekInstance();
if (imm != null) imm.restartInput(this);
将软键盘重置了,故使用的软键盘是其自己getInputType方法得到的数字键盘模式。
为什么会弹出数字键盘已经分析完了,这样大家觉得大功告成了?还没完!
应该说大部分输入法的数字键盘都可以返回到全键盘的,但是有少数输入法(比如:三星输入法)不能切换回去!
可能有人想要在后面再给EditText设置setInputType(InputType.TYPE_CLASS_TEXT);让其弹出全键盘,结果是:虽然弹出了全键盘,但是之前设置的digits限制失效了!原因是:
/**TextView 里面的setInputType方法*/
public void setInputType(int type) {
……
//这里相当于从新设置了软键盘模式
InputMethodManager imm = InputMethodManager.peekInstance();
if (imm != null) imm.restartInput(this);
}
setInputType方法将软键盘重置成全键盘模式,前面设置的DigitsKeyListener 完全失效!
如果想要在代码里面实现设置输入字符的限制(digits)就只能弹出数字键盘,而数字键盘并不是所有都能返回到全键盘,所以,这种方法并不可行,原因是android没有为DigitsKeyListener提供设置inputType这样的接口
如果有高手找出更好的方法,欢迎留言点评,博主将感激不尽!!!
原文地址:http://blog.csdn.net/u013210543/article/details/45868675