美文网首页
EditText自定义InputFilter完全解析----推荐

EditText自定义InputFilter完全解析----推荐

作者: 一整块儿腹肌 | 来源:发表于2018-11-20 10:58 被阅读0次

    一、简述

    监听EditText的输入是一个十分常见的需求,但是使用setOnEditorActionListener、addTextChangedListener等接口来监听输入不够灵活,而且如果有多种过滤条件,则方法里的逻辑会非常复杂。

    推荐使用实现自己输入过滤器来过滤输入内容,使用方便、灵活,而且官方已经实现了许多常用的过滤器。

    InputFilter

    public interface InputFilter

    android.text.InputFilter

    Known indirect subclasses

    DateKeyListener, DateTimeKeyListener, DialerKeyListener, DigitsKeyListener, InputFilter.AllCaps, InputFilter.LengthFilter, LoginFilter, LoginFilter.PasswordFilterGMail, LoginFilter.UsernameFilterGMail, LoginFilter.UsernameFilterGeneric, NumberKeyListener, TimeKeyListener

    使用方法

    //通过EditText 的setFilters方法设置,可以传入多个Filter
    
    setFilters(new InputFilter[]{new LengthFilter(maxLength),new CustomFilter()});
    

    二、详细讲解InputFilter API,和如何自定义一个InputFilter

    首先这是API的链接(需要翻墙 如果看不到也没关系,下面有详细内容)

    https://developer.android.com/reference/android/text/InputFilter

    API中的定义

    /**
    * 当缓冲区要使用source的[start - end)范围内的内容替换dest的[dstart - dend)范围内的内容时调用该方法。
    * 返回值是你最终想要添加的文本。如果返回空字符"",则不添加新内容。如果返回空(null),则添加本次输入的全部内容(即source)
    * 当你在删除已有文本时,source的长度为0。不要以为是错误而过滤这种清空。
    * 不要直接修改dest的内容,它的内容只是用来查看的。
    */
    public CharSequence filter(CharSequence source, int start, int end,
    Spanned dest, int dstart, int dend);
    

    方法描述:

    使用source的下标范围[start--end)的内容,替换dest的下标范围是[dstart-dend)的内容。两个区间都是左闭右开 .end-start是本次输入的字数,dend-dstart是本次被替换的字数。

    参数说明:

    CharSequence source :本次输入内容

    int start :本次输入被选择的起始位置

    int end:本次输入被选择的结束位置(不包含)

    Spanned dest : 当前输入框中的内容

    int dstart :被替换内容在输入框中的起始位置

    int dend :被替换内容在输入框中的结束位置(不包含)

    返回值说明:

    返回值是本次输入最终被输入的内容。有以下三种情况

    1. 返回空字符串:""。 放弃本次输入,即本次输入不会添加到输入框中
    2. **返回空值:null。 **将本次输入完全完全添加到输入框中,相当于return source(不建议使用return source)
    3. **返回指定有内容的字符串:你希望的输入(如"12345")。 **次将指定的字符串添加到输入框中(如"12345")

    声明:

    被替换内容是指:当选择输入框里的内容,然后输入新的字符,选择的内容将会被新输入的字符替换。这些选择的内容就是被替换的内容。




    如果觉得参数不好理解,参考下面的输入实例。

    本次输入 b

    source = b
    start = 0, end =1
    dest =
    dstart = 0, dend =0

    本次输入n

    source = n
    start = 0, end =1
    dest = b
    dstart = 1, dend =1

    本次输入 m

    source = m
    start = 0, end =1
    dest = bn
    dstart = 2, dend =2

    本次输入 s

    source = s
    start = 0, end =1
    dest = bnm
    dstart = 3, dend =3

    本次输入 s

    source = s
    start = 0, end =1
    dest = bnms
    dstart = 4, dend =4

    本次输入 s

    source = s
    start = 0, end =1
    dest = bnmss
    dstart = 5, dend =5

    本次输入 孙健

    source = 孙健
    start = 0, end =2
    dest = bnmsss
    dstart = 6, dend =6

    本次输入 刘德华

    source = 刘德华
    start = 0, end =3
    dest = bnmsss孙健
    dstart = 8, dend =8

    输入前选中 【刘德华】 然后输入 【张学友****】替换【刘德华】

    source = 张学友
    start = 0, end =3
    dest = bnmsss孙健刘德华
    dstart = 8, dend =11

    输入前选中 【张学友】**** 然后输入 【黎明****】替换【张学友】

    source = 黎明
    start = 0, end =2
    dest = bnmsss孙健张学友
    dstart = 8, dend =11




    参数看懂了,我们就来了解一下如何来自定义我们需要的过滤器。

    以SDK中已经提供的输入长度过滤器LengthFilter来作为例子,看一下是如何实现限制输入字数的。

    /**
     * This filter will constrain edits not to make the length of the text
     * greater than the specified length.
     */
    public static class LengthFilter implements InputFilter {
        private final int mMax;
    
        public LengthFilter(int max) {
            mMax = max;
        }
    
        public CharSequence filter(CharSequence source, int start, int end, Spanned dest,
                int dstart, int dend) {
            int keep = mMax - (dest.length() - (dend - dstart));  //剩余可以输入的字数
            if (keep <= 0) {
                return ""; //如果没有剩余可输入字数   则保持原有文本不变
            } else if (keep >= end - start) {
                // keep original   如果剩余可输入字数大于当前正在输入的字数    则返回当前输入   
                //(相当于 return source,不过不建议这么写)
                return null; 
            } else {//如果当前输入大于剩余可输入字数,则截取当前输入的剩余可输入字数的字符作为返回值
                keep += start;
                if (Character.isHighSurrogate(source.charAt(keep - 1))) {
                    --keep;
                    if (keep == start) {
                        return "";
                    }
                }
                return source.subSequence(start, keep);
            }
        }
    
        /**
         * @return the maximum length enforced by this input filter
         */
        public int getMax() {
            return mMax;
        }
    }
    
    

    上面的注释代码已经详细说明了如何实现filter()方法。


    三、定义一个只能输入数字的过滤器

    思路:

    数字在ASCII中的分为是[48,57],只要在该范围内都是数字。

    代码实现:

    //通过匿名内部类的方法来实现。如果考虑复用,可以单独声明一个类
    InputFilter DigitalFilter = new InputFilter() {
                @Override
                public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
    
                    if(source.length() <= 0){return "";}
    
                    char [] newChar = new char[source.length()];
    
                    //去掉source中不是数字的字符
                    for(int i=source.length();--i>=0;){
                        int chr=source.charAt(i);
                        if(chr > 47 && chr < 58){
                            newChar[i] = (char) chr;
                        }
    
                    }
    
                    //newChar数组中没有赋值的项,在转换为String会被丢弃
                    return new String(newChar);
                }
            };
    



    总结:


    其实自定义过滤器的难点是理解filter接口的各个参数的意义和返回值表达的含义(api定义注释里的三种情况:""空字符串、null空值、有内容字符串)。我翻译的注释里其实已经解释的很清楚了,如果不要理解看了下面的实际输入的例子应该也能理解了。

    只要理解上述内容,根据自己的实际需求返回合适的值即可。

    相关文章

      网友评论

          本文标题:EditText自定义InputFilter完全解析----推荐

          本文链接:https://www.haomeiwen.com/subject/rietqqtx.html