InputFilter实现EditText过滤中文字符、空格等特殊字符

最近项目要求EditText输入文字时过滤掉中文字符、空格等特殊字符,上网查了好多资料,最后决定使用IputFilter来实现这一功能,写一篇博客来记录一下自己的心得

先上效果图
InputFilter实现EditText过滤中文字符、空格等特殊字符_第1张图片

主要代码

public class NoMenuEditText extends EditText {
    private final Context context;
    private int maxLength;//自定义属性判断是输入字符的最大长度
    private boolean allow_blank;//自定义属性判断是否允许输入空格,默认false
    private boolean allow_chinese;//自定义属性判断是否允许输入中文


    public NoMenuEditText(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.context = context;
        init(attrs);
    }

    public NoMenuEditText(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        this.context = context;
        init(attrs);
    }

    private void init(AttributeSet attrs) {
        final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.NoMenuEditText);//加载自定义styleable文件
        maxLength = a.getInteger(R.styleable.NoMenuEditText_maxLength,0);//读取自定义属性输入字符的最大长度
        allow_blank = a.getBoolean(R.styleable.NoMenuEditText_allow_blank, false);//读取自定义属性是否允许输入空格
        allow_chinese = a.getBoolean(R.styleable.NoMenuEditText_allow_chinese,false);//读取自定义属性是否允许输入中文
        if (maxLength > 0){
            setFilters(new InputFilter[]{new LengthFilter(maxLength),new InputFilter() {
                @Override
                public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
                    if (!allow_blank){
                        if (source.equals(" ")) {
                            return "";
                        }
                    }
                    if (!allow_chinese){
                        if (checkNameChese(source.toString())){
                            return "";
                        }
                    }
                    return null;
                }
            }});

        }else {
            setFilters(new InputFilter[]{new InputFilter() {
                @Override
                public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
                    if (!allow_blank){
                        if (source.equals(" ")) {
                            return "";
                        }
                    }
                    if (!allow_chinese){
                        if (checkNameChese(source.toString())){
                            return "";
                        }
                    }
                    return null;
                }
            }});
        }
        this.setCustomSelectionActionModeCallback(new ActionModeCallbackInterceptor());
        this.setLongClickable(false);
    }

    private class ActionModeCallbackInterceptor implements ActionMode.Callback {

        private final String TAG = NoMenuEditText.class.getSimpleName();

        @Override
        public boolean onCreateActionMode(ActionMode mode, Menu menu) {
            return false;
        }

        @Override
        public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
            return false;
        }

        @Override
        public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
            return false;
        }

        @Override
        public void onDestroyActionMode(ActionMode mode) {

        }
    }


    public boolean stringFilter(String str){
        // 只允许字母、数字和汉字
        String   regEx  =  "[^\u4E00-\u9FA5]";
        Pattern   p   =   Pattern.compile(regEx);
        Matcher m   =   p.matcher(str);
        return   m.matches();
    }

    /**
     * 判定输入汉字
     * @param c
     * @return
     */
    public  boolean isChinese(char c) {
        Character.UnicodeBlock ub = Character.UnicodeBlock.of(c);
        if (ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS
                || ub == Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS
                || ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A
                || ub == Character.UnicodeBlock.GENERAL_PUNCTUATION
                || ub == Character.UnicodeBlock.CJK_SYMBOLS_AND_PUNCTUATION
                || ub == Character.UnicodeBlock.HALFWIDTH_AND_FULLWIDTH_FORMS) {
            return true;
        }
        return false;
    }

    /**
     * 检测String是否全是中文
     * @param name
     * @return
     */
    public  boolean checkNameChese(String name)
    {
        boolean res=false;
        char [] cTemp = name.toCharArray();
        for(int i=0;iif(isChinese(cTemp[i]))
            {
                res=true;
                break;
            }
        }
        return res;
    }
}

自定义属性文件在attrs.xml文件中

<declare-styleable name="NoMenuEditText">
        <attr name="allow_blank" format="boolean" />
        <attr name="maxLength" format="integer" />
        <attr name="allow_chinese" format="boolean" />
    declare-styleable>

XML布局中的使用方式

<com.xfzd.client.user.view.NoMenuEditText
                xmlns:aa="http://schemas.android.com/apk/res-auto/com.xfzd.client"
                aa:allow_blank="true"
                aa:maxLength="20"

代码分析

上述代码8-11,14-18分别是自定义EditText构造函数当中都有一个初始化init(attrs)方法,我们在此方法中实现自定义属性的解析,和自定义InputFilter过滤器的实现

InputFilter实现EditText过滤中文字符、空格等特殊字符_第2张图片
20行代码,可能到家会对自定义属性maxLength感到疑惑,因为EditText有一个属性android:maxLength=”19”为什么这里还要设置一个自定义属性,岂不是多此一举,我子啊这里要解释一下android:maxLength=”19”这个属性是在EditText的父类也就是TextView中使用到的,我们进入到TextView的代码中我们看一看
InputFilter实现EditText过滤中文字符、空格等特殊字符_第3张图片
这行代码实在TextView的构造函数中,其中maxLength就是解析TextView属性android:maxLength的到的值,我们在这里可以看到此处会根据maxLength的长度来用不同的策略来设置InputFilters这个数组,最后在通过setFilters()这个方法去设置TextView的过滤器,我们看到maxLength长度大于0时,会给InputFilter[]数组设置一个成员new InputFilter.LengthFilter(maxlength) TextView和EidtText正是由于设置了这样一个InputFilter才实现文字长度的限制
InputFilter实现EditText过滤中文字符、空格等特殊字符_第4张图片
进入到LengthFilter的源码中我们发现LengthFilter 实现了 InputFilter这个接口并实现了filter()这个方法,因此才能实现对TextView、EditText的字符长度的限制。我门今天实现的就是通过自定InputFilter实现EditText过滤中文、空格等特殊字符,而这其中的关键也是在于实现InputFilter接口通过实现filter()这个方法,来达到实现字符的过滤

我们还是从最关键的地方Init函数分析

private void init(AttributeSet attrs) {
        final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.NoMenuEditText);//加载自定义styleable文件
        maxLength = a.getInteger(R.styleable.NoMenuEditText_maxLength,0);//读取自定义属性输入字符的最大长度
        allow_blank = a.getBoolean(R.styleable.NoMenuEditText_allow_blank, false);//读取自定义属性是否允许输入空格
        allow_chinese = a.getBoolean(R.styleable.NoMenuEditText_allow_chinese,false);//读取自定义属性是否允许输入中文
        if (maxLength > 0){
            setFilters(new InputFilter[]{new LengthFilter(maxLength),new InputFilter() {
                @Override
                public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
                    if (!allow_blank){
                        if (source.equals(" ")) {
                            return "";
                        }
                    }
                    if (!allow_chinese){
                        if (checkNameChese(source.toString())){
                            return "";
                        }
                    }
                    return null;
                }
            }});

        }else {
            setFilters(new InputFilter[]{new InputFilter() {
                @Override
                public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
                    if (!allow_blank){
                        if (source.equals(" ")) {
                            return "";
                        }
                    }
                    if (!allow_chinese){
                        if (checkNameChese(source.toString())){
                            return "";
                        }
                    }
                    return null;
                }
            }});
        }
        this.setCustomSelectionActionModeCallback(new ActionModeCallbackInterceptor());
        this.setLongClickable(false);
    }

6行判断maxLength 属性是否大于0(默认为0,大于0说明在布局xml中view的属性中设置过),接下来第7行setFilters(new InputFilter[])我们看到该方法的参数是一个InputFilter[]数组,实际上就是说可以通过多组合InputFilter来实现各种过滤的效果,我们实现的就是过滤中文字符和空字符串,所以我在数组的第二个变量中重写InputFilter的filter方法来实现这样的效果。filter过滤是通过返回值来决定的

  1. return “”
    表示过滤输入的内容
  2. return null
    表示不过滤输入的内容

我们看10行先判断是不允许输入空字符串,进入11行判断输入内容是为空字符串过滤,15行判断不允许输入中文进入16行判断输入内容为中文字符过滤,否则进入20行不进行过滤

你可能感兴趣的:(EditText过滤)