Android 输入框(EditText)的输入限制,数字英文邮箱,可见\隐藏切换,踩过的坑!

简介: 最近做到了登录注册模块的各种输入判定,监听等等,因为需求上的需要,还是搞了好一会儿,今天在这总结一下。常规的输入框输入需求有纯数字,字母,混合输入,邮箱,键盘默认打开数字键盘,密码可见性,键盘的收起弹出等等。

最近做到了登录注册模块的各种输入判定,监听等等,因为需求上的需要,还是搞了好一会儿,今天在这总结一下。


常规的输入框输入需求有纯数字,字母,混合输入,邮箱,键盘默认打开数字键盘,密码可见性,键盘的收起弹出等等。


一、输入框的输入限制


1.在xml文件里通过设置属性限制输入


1.inputType



例如:输入纯数字,则只需要在editText控件属性下加一句:

android:inputType="number"


常用的属性有:


android:inputType="none"输入普通字符
android:inputType="text"      输入普通字符
android:inputType="textCapCharacters"     输入普通字符
android:inputType="textCapWords"      单词首字母大小
android:inputType="textCapSentences"      仅第一个字母大小
android:inputType="textAutoCorrect"         前两个自动完成
android:inputType="textAutoComplete"    前两个自动完成
android:inputType="textMultiLine"      多行输入
android:inputType="textImeMultiLine"       输入法多行(不一定支持)
android:inputType="textNoSuggestions"   不提示
android:inputType="textUri"      URI格式
android:inputType="textEmailAddress"    电子邮件地址格式
android:inputType="textEmailSubject"    邮件主题格式
android:inputType="textShortMessage"    短消息格式
android:inputType="textLongMessage"     长消息格式
android:inputType="textPersonName"      人名格式
android:inputType="textPostalAddress"   邮政格式
android:inputType="textPassword"      密码格式
android:inputType="textVisiblePassword"     密码可见格式
android:inputType="textWebEditText"作为网页表单的文本格式
android:inputType="textFilter"              文本筛选格式
android:inputType="textPhonetic"        拼音输入格式
android:inputType="number"      数字格式
android:inputType="numberSigned"     有符号数字格式
android:inputType="numberDecimal"   可以带小数点的浮点格式
android:inputType="phone"      拨号键盘
android:inputType="datetime"  日期+时间格式
android:inputType="date"      日期键盘
android:inputType="time"      时间键盘

这个属性,配置后键盘会有不同的展现方式,根据手机的键盘软件自适应,有些属性会限制输入,有些则不会,例如number会限制你只能输入数字,textPassword会把输入的内容占位但不可见,就和输入QQ密码一样。


2.在xml里面设置digits属性



android:digits="!@#$qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM1234567890"

那么他就只能输入以上digits里面的内容.


2.在代码里动态设置输入限制


1.通过setKeyListener进行限制(kotlin)


editText.keyListener = DigitsKeyListener.getInstance("qwertyuiopasdfghjklzx"+
"cvbnmQWERTYUIOPASDFGHJKLZXCVBNM1234567890\\_~@#$^")

eg1:为啥会有两个\\呢,因为\是转义字符,所以第一个是拿来转义后面的\的。不了解转义字符的可以看下面链接:


2.判断邮箱格式


 

fun checkEditInput(string: String?): Boolean {
        val pattern = Pattern.compile("[A-Za-z\\d]+([-_.][A-Za-z\\d]+)*@([A-Za-z\\d]+[-.])+[A-Za-z\\d]{2,4}")
        return ((string?.length ?: 0) > 0) && pattern.matcher(string ?: "").matches()
    }

这个是写的正则表达式,用来判断邮箱格式的,返回的布尔值代表格式是否正确


3.通过InputFilter来过滤输入

val typeFilter = InputFilter { source, _, _, _, _, _ ->
// p: Pattern = Pattern.compile("[0-9a-zA-Z|\u4e00-\u9fa5]+")  //限制输入中英文,数字
 val p: Pattern = Pattern.compile("[0-9a-zA-Z|!@#$]+")//限制输入数字英文和部分特殊字符
 val m: Matcher = p.matcher(source.toString())
 if (!m.matches()) "" else null
 }
 searchEdit?.filters = arrayOf(typeFilter, InputFilter.LengthFilter(10))
 eg:上面的代码是kotlin哈,他其实是复写了里面的filter方法,这里我把java代码也粘出来。
 InputFilter typeFilter = new InputFilter() {
     @Override
     public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
     Pattern p = Pattern.compile("[0-9a-zA-Z|\u4e00-\u9fa5]+");
     Matcher m = p.matcher(source.toString());
     if (!m.matches()) return "";
     return null;
     }
   };
    //如果要限制输入字数,数组中加上new InputFilter.LengthFilter(maxLength)
    searchEdit.setFilters(new InputFilter[]{typeFilter, new         InputFilter.LengthFilter(10)});

解析:setFilters() 方法,传入的参数是一个filter列表,在上面代码中,为啥我后面又补了一个InputFilter.LengthFilter(10)呢,因为如果不加上这个,会让xml布局里面的maxLength属性失效,因为在TextVIew的源码的构造方法中有一个变量maxLength它对应xml中属性android:maxLength,如果有值就赋值给变量maxLength,如果大于等于0,就调用setFilters(),传入一个InputFilter.LengthFilter。但是我们又在自己的代码中又setFilters了,就把以前的属性替换掉了,所以,要在这儿补上去哦!


TextView源码:
public TextView(
            Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        ...
        int maxlength = -1;
        ...
        case com.android.internal.R.styleable.TextView_maxLength:
                    maxlength = a.getInt(attr, -1);
                    break;
        ...
        if (maxlength >= 0) {
            setFilters(new InputFilter[] { new InputFilter.LengthFilter(maxlength) });
        } else {
            setFilters(NO_FILTERS);
        }
        ...
}

关于Patter和Matcher的用法:

我爱学Java之Pattern和Matcher用法_Java.Sheng的博客-CSDN博客

Java正则表达式通过java.util.regex包下的Pattern和Matcher类实现Pattern类用于创建一个正则表达式,也可以说是创建一个匹配模式,可以通过两个静态方法创建:compile(String regex)和compile(String regex,int flags),其中regex是正则表达式,flags为可选模式(如:Pattern.CASE_INSENSITIVE 忽


4.代码里通过设置InputType


这个就和xml里属性设置差不多,不过代码里更加灵活。下面的代码就是动态设置输入内容可见/不可见,就是类似于QQ密码的那个眼睛图标的功能。


 

private fun setEditPassword(editText: EditText, passwordVisible: Boolean) {
        if (passwordVisible) { //选择状态 显示明文--设置为可见的密码
            editText.inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD
        } else { //默认状态显示密码--设置文本 要一起写才能起作用  InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD
            editText.inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_PASSWORD
        }
    }

以上就是输入限制的一些方法,可以根据需求打一套组合拳,但是有些方法也会有冲突导致失效,这时候就可以去看看源码。


二、密码可见性切换和遇到的坑


1.使用setKeyListner和inputType组合使用的冲突:


需求:1.对密码输入做限制2.密码可点击眼睛图标进行可见、隐藏。


限制代码


editText.keyListener = DigitsKeyListener.getInstance("qwertyuiopasdfghjklzx"+
"cvbnmQWERTYUIOPASDFGHJKLZXCVBNM1234567890\\_~@#$^")

点击事件进行密码隐藏

private fun setEditPassword(editText: EditText, passwordVisible: Boolean) {
        if (passwordVisible) { //选择状态 显示明文--设置为可见的密码
            editText.inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD
        } else { //默认状态显示密码--设置文本 要一起写才能起作用  InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD
            editText.inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_PASSWORD
        }
    }

冲突表现:点击图标进行切换后,原来的keyListener设置的限制失效,可以输入任意字符


原因看源码:在keyListener里,


public void setKeyListener(KeyListener input) {
        mListenerChanged = true;
        setKeyListenerOnly(input);
        fixFocusableAndClickableSettings();
        if (input != null) {
            createEditorIfNeeded();
            setInputTypeFromEditor();
        } else {
            if (mEditor != null) mEditor.mInputType = EditorInfo.TYPE_NULL;
        }
        InputMethodManager imm = getInputMethodManager();
        if (imm != null) imm.restartInput(this);
    }

看最后两行,这儿会将软键盘重置了,故使用的软键盘是其自己getInputType方法得到的数字键盘模式。


他的getInputType方法源码:

/**
     * Returns the input type for the listener.
     */
    public int getInputType() {
        int contentType;
        if (mNeedsAdvancedInput) {
            contentType = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_NORMAL;
        } else {
            contentType = InputType.TYPE_CLASS_NUMBER;
            if (mSign) {
                contentType |= InputType.TYPE_NUMBER_FLAG_SIGNED;
            }
            if (mDecimal) {
                contentType |= InputType.TYPE_NUMBER_FLAG_DECIMAL;
            }
        }
        return contentType;
    }

接下来:


 

public void setInputType(int type) {
        final boolean wasPassword = isPasswordInputType(getInputType());
       ......有点多我删了,看下面
        InputMethodManager imm = getInputMethodManager();
        if (imm != null) imm.restartInput(this);
    }

看最后两行,这儿setInputType方法将软键盘重置成全键盘模式,前面设置的DigitsKeyListener就失效了,变成新的。


解决办法1:在setEditPassword这个方法设置密码可见\隐藏后,再设置限制,这样就不会失效了,相当于每次点击图标切换,都会对输入框进行一次设定,相比于输入框的一些监听事件啊,这种操作也可以接受。(这个方法可能会因为inputType变化频繁导致部分手机的键盘切两次哦,所以这个方法不大完美!)


解决方法2:新的组合拳!!!InputFilter+setInputType


代码:将上面的setKeyListener干掉,用下面的方法限制,就完美结局了,有maxLength记得补上哦~

val typeFilter = InputFilter { source, start, end, dest, dstart, dend -> //限制只能输入中文,英文,数字
            //            val p: Pattern = Pattern.compile("[0-9a-zA-Z|\u4e00-\u9fa5]+")
            val p: Pattern = Pattern.compile("[0-9a-zA-Z|!@#$]+")
            val m: Matcher = p.matcher(source.toString())
            if (!m.matches()) "" else null
        }
       editText?.filters = arrayOf(typeFilter, InputFilter.LengthFilter(10))


这块的总结就到这儿了,有疑问的欢迎评论区讨论哈,有不对的地方望大佬指教!


相关文章
|
6月前
|
数据安全/隐私保护 Android开发 iOS开发
解决第三方邮箱APP登陆QQ、163邮箱无法验证账户名或密码的问题(IOS、MacOS、Windows、Android)
解决第三方邮箱APP登陆QQ、163邮箱无法验证账户名或密码的问题(IOS、MacOS、Windows、Android)
113 0
|
8月前
|
Android开发
Android 实现点击输入框以外的区域隐藏软键盘
Android 实现点击输入框以外的区域隐藏软键盘
95 0
|
8月前
|
Java Android开发
Android 中设置EditText输入框提示文本hint的字体大小
Android 中设置EditText输入框提示文本hint的字体大小
204 0
|
8月前
|
XML Java Android开发
Android 中通过Java代码动态生成EditText视图,并循环遍历EditText取出遍历的ID和文本框的值
Android 中通过Java代码动态生成EditText视图,并循环遍历EditText取出遍历的ID和文本框的值
102 0
|
8月前
|
Java Android开发 iOS开发
Android TextView 与 EditText 的区别与使用
Android TextView 与 EditText 的区别与使用
99 0
|
11月前
|
XML Android开发 数据格式
Android EditText 获取/失去焦点
项目的需求中,又一个4位数的验证码界面,小弟才疏学浅,只想到了用线性布局里面放四个EditText。 需求需要输入内容后,自动跳到下一个位置聚焦,删除指定位置后,自动跳到上一个位置聚焦,由于聚焦/非聚焦UI展示得都不同,所以每个editText都会频繁的设置焦点变化。 之前因为是调用的系统键盘,所以,editText和键盘绑定后处理起来非常方便,但是,我们需要自定义一个展示在UI上的数字键盘,于是就有些bug。 bug不难,但是有点杂乱,下面是我的一点解决办法,总结一下,以后也记得更清楚!
|
11月前
|
Android开发
Android EditText输入框不聚焦,点击跳转
Android EditText输入框不聚焦,点击跳转
|
XML Android开发 数据安全/隐私保护
Android开发之输入框EditText介绍
Android开发之输入框EditText介绍
305 0
|
Java Android开发 UED
android EditText长按屏蔽ActionMode context菜单但保留选择工具功能
最近项目要求屏蔽EditText 长按出来的ActionMode菜单,但是要保留选择文本功能。这个屏蔽百度会出现各种方法,这里说一下我的思路: 1.屏蔽百度可知setCustomSelectionActionModeCallback即可, editTextExt.
1115 0