Adroid EditText限制输入数字与英文默认弹出数字键盘

终于要写博客了,以前总觉得技术大牛才能写博客,后面想想,分享个人想法与技术探讨也是一种不错的交流方式。今天讲讲我在项目中遇到的一个实际需求,也许很多人也遇到过:

EditText要求限制输入数字和英文,但是最好默认弹出数字键盘。

我也上网搜过很多种方式,将自己的总结经验带给大家参考:

方法一 在xml里面设置 android:digits

android:digits="0123456789abcdefghigklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"

结果:可以实现限制输入数字和英文的效果,但是默认弹出的全键盘而不是数字键盘。

方法二 为EditText添加监听器

    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或者监听来限制输入数字和英文的,现在变成只能输入数字了!!!

方法三 设置EditText的KeyListener

通过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

你可能感兴趣的:(android开发)