Android自定义View——过滤表情等规则的EditText

这篇博客介绍了如何在Android中自定义一个EditText,以过滤表情符号并限制输入字符的类型和数量。作者通过继承EditText并设置自定义属性来实现这一功能,详细讲解了实现思路、关键代码和注意事项。

前言:需求来了,产品小姐姐展现其高超技能的时候到了,接下来就是闪(粉)亮(墨)登场的时候了,a.登录账号只能输入数字;b.限制下位数;c.密码只输入数字字母和标点符号,总不能输入汉字吧;d.还有那个哪里哪里 你就输入汉字和字母就行了,哪有人的名字有数字啊?e.最重要的是不能输入表情符号等等。针对多才多艺的产品小姐姐,我一个彪形大汉(会写代码的文艺青年)肯定会怜香惜玉一一满足。针对这一有规律的需求,决定自定义View重写EditText来实现之。

项目背景

不想说

需求

  1. 限制输入表情符号
  2. 限制输入字数限制
  3. 英文、汉字、数字等可以多个并存限制字数和输入类型

实现思路

自定义View继承EditText,通过自定义属性来设置过滤器Filter控制输入类型和个数的限制。废话不多说直接上代码:

 

自定义属性如下:

<declare-styleable name="HandyEmojiEdittext">
        <!-- 是否限制输入表情符号 默认限制 -->
        <attr name="emojiFilterable" format="boolean|reference" />
        <!-- 是否过滤空格 默认不过滤 -->
        <attr name="filterSpace" format="boolean|reference" />
        <!-- 输入长度 -->
        <attr name="inputLength" format="integer|reference" />
        <!-- 输入类型 -->
        <attr name="inputTypeEnum">
            <flag name="none" value="0x00" /><!--0000 0000-->
            <flag name="en" value="0x01" /><!--0000 0001-->
            <flag name="zh" value="0x02" /><!--0000 0010-->
            <flag name="num" value="0x04" /><!--0000 0100-->
        </attr>
        <!-- 输入的最大整数 -->
        <attr name="maxNum" format="integer|reference" />
    </declare-styleable>

需要注意的是,inputTypeEnum 输入类型限制设置属性值的时候 跟TextView android:gravity="start|end" 使用规则一样,eg:app:inputTypeEnum="en|zh" 所以value只能是2^n

属性inputTypeEnum解释

算了~不解释了 ~

自己看~很简单的~

inputTypeEnum = typedArray.getInt(R.styleable.HandyEmojiEdittext_inputTypeEnum, 0);
 switch (inputTypeEnum) {
            case 0://none
                inputTypeFilter = null;
                break;
            case 1://en
                inputTypeFilter = new InputFilter() {
                    Pattern inputTypePattern = Pattern.compile(
                            "[a-zA-Z]",
                            Pattern.UNICODE_CASE | Pattern.CASE_INSENSITIVE);

                    @Override
                    public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
                        Matcher inputTypeMather = inputTypePattern.matcher(source);
                        if (inputTypeMather.find()) {
                            return source;
                        }
                        return "";
                    }
                };
                break;
            case 2://zh
                inputTypeFilter = new InputFilter() {
                    Pattern inputTypePattern = Pattern.compile(
                            "[\u4e00-\u9fa5]",
                            Pattern.UNICODE_CASE | Pattern.CASE_INSENSITIVE);

                    @Override
                    public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
                        Matcher inputTypeMather = inputTypePattern.matcher(source);
                        if (inputTypeMather.find()) {
                            return source;
                        }
                        return "";
                    }
                };
                break;
            case 3://en & zh
                inputTypeFilter = new InputFilter() {
                    Pattern inputTypePattern = Pattern.compile(
                            "[a-zA-Z|\u4e00-\u9fa5]",
                            Pattern.UNICODE_CASE | Pattern.CASE_INSENSITIVE);

                    @Override
                    public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
                        Matcher inputTypeMather = inputTypePattern.matcher(source);
                        if (inputTypeMather.find()) {
                            return source;
                        }
                        return "";
                    }
                };
                break;
            case 4://num
                inputTypeFilter = new InputFilter() {
                    Pattern inputTypePattern = Pattern.compile(
                            "[0-9]",
                            Pattern.UNICODE_CASE | Pattern.CASE_INSENSITIVE);

                    @Override
                    public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
                        Matcher inputTypeMather = inputTypePattern.matcher(source);
                        if (inputTypeMather.find()) {
                            if (maxNum != -1 && dest != null && !StringUtils.isEmpty(dest.toString().trim())) {
                                if (Integer.parseInt(dest.toString().trim() + source) <= maxNum) {
                                    return source;
                                } else {
                                    return "";
                                }
                            }
                            return source;
                        }
                        return "";
                    }
                };
                break;
            case 5://en & num
                inputTypeFilter = new InputFilter() {
                    Pattern inputTypePattern = Pattern.compile(
                            "[a-zA-Z|0-9]",
                            Pattern.UNICODE_CASE | Pattern.CASE_INSENSITIVE);

                    @Override
                    public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
                        Matcher inputTypeMather = inputTypePattern.matcher(source);
                        if (inputTypeMather.find()) {
                            return source;
                        }
                        return "";
                    }
                };
                break;
            case 6://zh & num
                inputTypeFilter = new InputFilter() {
                    Pattern inputTypePattern = Pattern.compile(
                            "[\u4e00-\u9fa5|0-9]",
                            Pattern.UNICODE_CASE | Pattern.CASE_INSENSITIVE);

                    @Override
                    public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
                        Matcher inputTypeMather = inputTypePattern.matcher(source);
                        if (inputTypeMather.find()) {
                            return source;
                        }
                        return "";
                    }
                };
                break;
            case 7://en & zh & num
                inputTypeFilter = new InputFilter() {
                    Pattern inputTypePattern = Pattern.compile(
                            "[0-9|a-zA-Z|\u4e00-\u9fa5]",
                            Pattern.UNICODE_CASE | Pattern.CASE_INSENSITIVE);

                    @Override
                    public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
                        Matcher inputTypeMather = inputTypePattern.matcher(source);
                        if (inputTypeMather.find()) {
                            return source;
                        }
                        return "";
                    }
                };
                break;
            default:
                inputTypeFilter = null;
                break;
        }

解释:en对应的value是1(0000 0001) zh对应的value是2(0000 0010), 则  en|zh=3(0000 0011)

 

过滤表情符号

敲黑板

if (emojiFilterable) {
            emojiFilter = new InputFilter() {
                Pattern emoji = Pattern.compile(
                        "[\ud83c\udc00-\ud83c\udfff]|[\ud83d\udc00-\ud83d\udfff]|[\u2600-\u27ff]",
                        Pattern.UNICODE_CASE | Pattern.CASE_INSENSITIVE);

                @Override
                public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
                    Matcher emojiMatcher = emoji.matcher(source);
                    if (emojiMatcher.find()) {
                        return "";
                    }
                    return source;
                }
            };
        }

 

注意

由于是通过设置filter来实现输入限制的规则,那么就不能丢弃原有textview的filter,所以setFilters()方法追加filter来处理

 InputFilter[] filters = new InputFilter[size + getFilters().length];

        int i = 0;
        for (InputFilter f : getFilters()) {
            filters[i++] = f;
        }
        if (emojiFilter != null) {
            filters[i++] = emojiFilter;
        }
        if (lengthFilter != null) {
            filters[i++] = lengthFilter;
        }
        if (inputTypeFilter != null) {
            filters[i++] = inputTypeFilter;
        }
        if (spaceFilter != null) {
            filters[i] = spaceFilter;
        }
        setFilters(filters);

 

为了小伙伴的拿来主义,该自定义view的全部代码如下:

/**
 * 描述:
 * <p>
 * 中英文
 * [a-zA-Z|\u4e00-\u9fa5]
 * 英文
 * [a-zA-Z]
 *
 * @author coo_fee.
 * @Time 2019/7/9.
 */
@SuppressLint("AppCompatCustomView")
public class HandyEmojiEdittext extends EditText {

    /**
     * 是否过滤表情
     * true 默认过滤
     */
    boolean emojiFilterable = true;

    /**
     * 是否过滤空格
     * false 默认不过滤
     */
    boolean mFilterSpace = false;
    /**
     * 输入长度限制
     * <=0 表示没有限制
     */
    int inputLength = 0;
    /**
     * 输入类型
     * 0 none 没有限制
     * 1 en 限制为英文
     * 2 zh 限制为中文
     * 3 en|zh 中文和英文
     */
    int inputTypeEnum = 0;

    /**
     * 输入的最大整数
     * -1 表示无限制
     */
    int maxNum = -1;

    public HandyEmojiEdittext(Context context) {
        super(context);
        init(context, null);
    }

    public HandyEmojiEdittext(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context, attrs);
    }

    public HandyEmojiEdittext(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context, attrs);
    }

    private void init(Context context, AttributeSet attrs) {
        if (attrs != null) {
            TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.HandyEmojiEdittext);
            emojiFilterable = typedArray.getBoolean(R.styleable.HandyEmojiEdittext_emojiFilterable, true);
            inputLength = typedArray.getInt(R.styleable.HandyEmojiEdittext_inputLength, 0);
            inputTypeEnum = typedArray.getInt(R.styleable.HandyEmojiEdittext_inputTypeEnum, 0);
            maxNum = typedArray.getInteger(R.styleable.HandyEmojiEdittext_maxNum, -1);
            mFilterSpace = typedArray.getBoolean(R.styleable.HandyEmojiEdittext_filterSpace, false);
        }
        InputFilter emojiFilter = null;
        InputFilter lengthFilter = null;
        InputFilter inputTypeFilter = null;
        InputFilter spaceFilter = null;
        if (emojiFilterable) {
            emojiFilter = new InputFilter() {
                Pattern emoji = Pattern.compile(
                        "[\ud83c\udc00-\ud83c\udfff]|[\ud83d\udc00-\ud83d\udfff]|[\u2600-\u27ff]",
                        Pattern.UNICODE_CASE | Pattern.CASE_INSENSITIVE);

                @Override
                public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
                    Matcher emojiMatcher = emoji.matcher(source);
                    if (emojiMatcher.find()) {
                        return "";
                    }
                    return source;
                }
            };
        }

        if (mFilterSpace) {
            spaceFilter = new InputFilter() {
                Pattern space = Pattern.compile(
                        " ",
                        Pattern.UNICODE_CASE | Pattern.CASE_INSENSITIVE);

                @Override
                public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
                    Matcher spaceMatcher = space.matcher(source);
                    if (spaceMatcher.find()) {
                        return "";
                    }
                    return source;
                }
            };
        }

        if (inputLength > 0) {
            lengthFilter = new InputFilter.LengthFilter(inputLength);
        }
        switch (inputTypeEnum) {
            case 0://none
                inputTypeFilter = null;
                break;
            case 1://en
                inputTypeFilter = new InputFilter() {
                    Pattern inputTypePattern = Pattern.compile(
                            "[a-zA-Z]",
                            Pattern.UNICODE_CASE | Pattern.CASE_INSENSITIVE);

                    @Override
                    public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
                        Matcher inputTypeMather = inputTypePattern.matcher(source);
                        if (inputTypeMather.find()) {
                            return source;
                        }
                        return "";
                    }
                };
                break;
            case 2://zh
                inputTypeFilter = new InputFilter() {
                    Pattern inputTypePattern = Pattern.compile(
                            "[\u4e00-\u9fa5]",
                            Pattern.UNICODE_CASE | Pattern.CASE_INSENSITIVE);

                    @Override
                    public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
                        Matcher inputTypeMather = inputTypePattern.matcher(source);
                        if (inputTypeMather.find()) {
                            return source;
                        }
                        return "";
                    }
                };
                break;
            case 3://en & zh
                inputTypeFilter = new InputFilter() {
                    Pattern inputTypePattern = Pattern.compile(
                            "[a-zA-Z|\u4e00-\u9fa5]",
                            Pattern.UNICODE_CASE | Pattern.CASE_INSENSITIVE);

                    @Override
                    public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
                        Matcher inputTypeMather = inputTypePattern.matcher(source);
                        if (inputTypeMather.find()) {
                            return source;
                        }
                        return "";
                    }
                };
                break;
            case 4://num
                inputTypeFilter = new InputFilter() {
                    Pattern inputTypePattern = Pattern.compile(
                            "[0-9]",
                            Pattern.UNICODE_CASE | Pattern.CASE_INSENSITIVE);

                    @Override
                    public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
                        Matcher inputTypeMather = inputTypePattern.matcher(source);
                        if (inputTypeMather.find()) {
                            if (maxNum != -1 && dest != null && !StringUtils.isEmpty(dest.toString().trim())) {
                                if (Integer.parseInt(dest.toString().trim() + source) <= maxNum) {
                                    return source;
                                } else {
                                    return "";
                                }
                            }
                            return source;
                        }
                        return "";
                    }
                };
                break;
            case 5://en & num
                inputTypeFilter = new InputFilter() {
                    Pattern inputTypePattern = Pattern.compile(
                            "[a-zA-Z|0-9]",
                            Pattern.UNICODE_CASE | Pattern.CASE_INSENSITIVE);

                    @Override
                    public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
                        Matcher inputTypeMather = inputTypePattern.matcher(source);
                        if (inputTypeMather.find()) {
                            return source;
                        }
                        return "";
                    }
                };
                break;
            case 6://zh & num
                inputTypeFilter = new InputFilter() {
                    Pattern inputTypePattern = Pattern.compile(
                            "[\u4e00-\u9fa5|0-9]",
                            Pattern.UNICODE_CASE | Pattern.CASE_INSENSITIVE);

                    @Override
                    public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
                        Matcher inputTypeMather = inputTypePattern.matcher(source);
                        if (inputTypeMather.find()) {
                            return source;
                        }
                        return "";
                    }
                };
                break;
            case 7://en & zh & num
                inputTypeFilter = new InputFilter() {
                    Pattern inputTypePattern = Pattern.compile(
                            "[0-9|a-zA-Z|\u4e00-\u9fa5]",
                            Pattern.UNICODE_CASE | Pattern.CASE_INSENSITIVE);

                    @Override
                    public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
                        Matcher inputTypeMather = inputTypePattern.matcher(source);
                        if (inputTypeMather.find()) {
                            return source;
                        }
                        return "";
                    }
                };
                break;
            default:
                inputTypeFilter = null;
                break;
        }
        int size = 0;
        if (emojiFilter != null) {
            ++size;
        }
        if (lengthFilter != null) {
            ++size;
        }
        if (inputTypeFilter != null) {
            ++size;
        }
        if (spaceFilter != null) {
            ++size;
        }
        InputFilter[] filters = new InputFilter[size + getFilters().length];

        int i = 0;
        for (InputFilter f : getFilters()) {
            filters[i++] = f;
        }
        if (emojiFilter != null) {
            filters[i++] = emojiFilter;
        }
        if (lengthFilter != null) {
            filters[i++] = lengthFilter;
        }
        if (inputTypeFilter != null) {
            filters[i++] = inputTypeFilter;
        }
        if (spaceFilter != null) {
            filters[i] = spaceFilter;
        }
        setFilters(filters);
    }
}

StringUtils.isEmpty()如下:

public static boolean isEmpty(String str) {
        return str == null || str.trim().length() == 0;
    }

 

写在最后的话

无论多么帅气的代码,都抵挡不住测试兄弟们的骚操作,所以在他手贱复制过来粘贴的时候就不显灵了,欢迎小伙伴们留言、点赞、交流。

 

 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值