Android自定义XEditText实现手机号空格输入

 自定义XeditText


public class XEditText extends android.support.v7.widget.AppCompatEditText {
    private static final int DRAWABLE_LEFT = 0;
    private static final int DRAWABLE_TOP = 1;
    private static final int DRAWABLE_RIGHT = 2;
    private static final int DRAWABLE_BOTTOM = 3;

    @Retention(RetentionPolicy.SOURCE)
    @IntDef({
            DelIconShowTime.ALWAYS_SHOW,
            DelIconShowTime.ALWAYS_HIND,
            DelIconShowTime.HAS_CONTENT_SHOW,
            DelIconShowTime.HAS_CONTENT_FOCUS_SHOW,
    })
    public @interface DelIconShowTime {
        /**
         * 总是显示右边删除图片(一直显示)
         */
        int ALWAYS_SHOW = 0x0000;
        /**
         * 总是隐藏右边图片(不显示)
         */
        int ALWAYS_HIND = 0x0001;
        /**
         * 有内容时显示(不管是否有焦点)
         */
        int HAS_CONTENT_SHOW = 0x0002;
        /**
         * 有内容并且有焦点时显示
         */
        int HAS_CONTENT_FOCUS_SHOW = 0x0003;
    }

    /**
     * 默认分隔符,{@code ' '} 表示
     */
    private static final char DEFAULT_SPLIT = ' ';
    /**
     * 实际分隔符
     */
    private char mSplitChar = DEFAULT_SPLIT;
    /**
     * 分隔符所在位置的数组
     */
    private int[] mSplitPosition;
    /**
     * 输入之前的长度
     */
    private int mPreLength;
    /**
     * 当前的长度
     */
    private int mCurrentLen;
    /**
     * EditText输入框的最大长度,当设置了模板的时候可以不用设置,因为会根据模板计算出最大的长度
     */
    private int mMaxLength;
    /**
     * 内容改变监听对象
     */
    private MyTextWatcher mTextWatcher;
    /**
     * 自定义的文字改变监听对象
     */
    private OnTextChangeListener mOnTextChangeListener;
    /**
     * 自定义焦点改变监听对象
     */
    private OnMyFocusChangeListener mOnMyFocusChangeListener;
    /**
     * 指定右边删除图片显示的时间,默认有内容并且有焦点时显示
     */
    private int mDelIconTime = DelIconShowTime.HAS_CONTENT_FOCUS_SHOW;
    /**
     * 右边删除按钮图片对象
     */
    private Drawable mClearDrawable;
    private Drawable[] mCompoundDrawables;

    /**
     * 提供默认的几个模板(包括中国大陆手机、最多19位的银行卡、18位身份证号)
     */
    public enum XTemplate {
        /**
         * 大陆手机格式(11位 3,4,4)
         */
        PHONE,
        /**
         * 银行卡号(最多19位 4,4,4,4,3)
         */
        BANK_CARD,
        /**
         * 省份证号(18位 4,4,4,4,2)
         */
        ID_CARD
    }

    public XEditText(Context context) {
        this(context, null);
    }

    public XEditText(Context context, AttributeSet attrs) {
        this(context, attrs, android.R.attr.editTextStyle);
    }

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

    /**
     * 初始化属性
     *
     * @param attrs
     */
    private void initAttr(AttributeSet attrs) {
        TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.XEditText);
        mMaxLength = typedArray.getInteger(R.styleable.XEditText_maxLength, 0);
        int xTemplate = typedArray.getInteger(R.styleable.XEditText_x_template, -1);
        String splitChar = typedArray.getString(R.styleable.XEditText_splitChar);
        String customTemplate = typedArray.getString(R.styleable.XEditText_custom_template);
        mClearDrawable = typedArray.getDrawable(R.styleable.XEditText_del_icon);
        mDelIconTime = typedArray.getInt(R.styleable.XEditText_del_show_time, DelIconShowTime.HAS_CONTENT_FOCUS_SHOW);
        // 校验和设置自定义的属性
        setCustomAttrs(xTemplate, splitChar, customTemplate);
        typedArray.recycle();
    }

    /**
     * 检验的设置自定的属性
     */
    private void setCustomAttrs(int xTemplate, String splitChar, String customTemplate) {
        // 校检设置的预定义模板
        if (xTemplate > 0) {
            if (1 == xTemplate) setXTemplate(XTemplate.PHONE);
            else if (2 == xTemplate) setXTemplate(XTemplate.BANK_CARD);
            else if (3 == xTemplate) setXTemplate(XTemplate.ID_CARD);
        }
        // 右边清除图片
        if (null == mClearDrawable) { // 没有定义就使用默认的图片
            // mClearDrawable = getContext().getResources().getDrawable(R.mipmap.icon_delete,null);
            mClearDrawable = getContext().getResources().getDrawable(R.mipmap.icon_delete);
        }
        mClearDrawable.setBounds(0, 0, mClearDrawable.getIntrinsicWidth(), mClearDrawable.getIntrinsicHeight());
        mCompoundDrawables = getCompoundDrawables();
        mClearDrawable.setVisible(false, false); // 最开始默认隐藏
        setCompoundDrawables(mCompoundDrawables[DRAWABLE_LEFT], mCompoundDrawables[DRAWABLE_TOP],
                mClearDrawable.isVisible() ? mClearDrawable : null,
                mCompoundDrawables[DRAWABLE_BOTTOM]);
        // 校检分隔符
        if (!TextUtils.isEmpty(splitChar)) mSplitChar = splitChar.charAt(0);
        // 校验自定义模板格式
        if (!TextUtils.isEmpty(customTemplate) && customTemplate.contains(",")) {
            String[] splits = customTemplate.split(",");
            int length = splits.length;
            if (length > 1) {
                int[] arr = new int[length];
                try {
                    for (int i = 0; i < length; i++) {
                        arr[i] = Integer.parseInt(splits[i]);
                    }
                    setTemplate(arr);
                } catch (NumberFormatException e) {
                    e.printStackTrace();
                    if (BuildConfig.DEBUG)
                        Log.e("XEditText", "自定义模板格式错误,请检查布局文件中的 custom_template属性是否参照格式定义");
                }
            }
        }
    }

    /**
     * 初始化其他的相关内容
     */
    private void init() {
        // 如果设置 inputType="number" 的话是没法插入空格的,所以强行转为inputType="phone"
        if (getInputType() == InputType.TYPE_CLASS_NUMBER)
            setInputType(InputType.TYPE_CLASS_PHONE);

        // 初始化并设置监听
        mTextWatcher = new MyTextWatcher();
        addTextChangedListener(mTextWatcher);

        // 焦点改变监听
        focusChangeListener();
    }

    /**
     * 焦点改变监听
     */
    private void focusChangeListener() {
        setOnFocusChangeListener(new OnFocusChangeListener() {
            @Override
            public void onFocusChange(View v, boolean hasFocus) {
                changeDelShowStatus(getText(), hasFocus);
                if (null != mOnMyFocusChangeListener)
                    mOnMyFocusChangeListener.onFocusChange(v, hasFocus);
            }
        });
    }

    /**
     * 设置右边删除图片
     *
     * @param delDrawable 右边的图片
     * @return
     */
    public XEditText setDelDrawable(@NonNull Drawable delDrawable) {
        if (delDrawable == null) return this;
        this.mClearDrawable = delDrawable;
        return this;
    }

    /**
     * 设置右边删除图片资源id
     *
     * @param delDrawableId 右边的图片资源id
     * @return
     */
    public XEditText setDelDrawable(int delDrawableId) {
        this.mClearDrawable = getResources().getDrawable(delDrawableId);
        return this;
    }

    /**
     * 设置右边删除图片显示的时间,默认有内容并且有焦点时显示
     *
     * @param delIconTime 设置右边删除图片显示的时间
     * @return
     */
    public XEditText setDelIconShowTime(@DelIconShowTime int delIconTime) {
        this.mDelIconTime = delIconTime;
        return this;
    }

    /**
     * 设置EditText输入内容的最大长度<br/>
     * <b>注意:</b><br/>
     * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
     * <b>1.如果调用了{@code setTemplate(@NonNull int[] template)}方法设置了模板时可以不用在设置最大长度,因为设置了模板会根据模板计算出最大的长度</b><br/>
     * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
     * <b>2.如果调用了{@code setTemplate(@NonNull int[] template)}方法设置了模板的同时,还要设置最大长度,一定要加上分割符的长度(分隔符也占用EditText的长度)</b><br/>
     *
     * @param maxLength 最大长度
     * @return
     * @see #setTemplate(int[])
     */
    public XEditText setMaxLength(int maxLength) {
        if (maxLength <= 0)
            throw new IllegalArgumentException("maxLength 的值必须大于 0");
        this.mMaxLength = maxLength;
        return this;
    }

    /**
     * 设置已经定义好的模板 {@link XTemplate},分割符为 ' '<br/>
     * <b>如果既设置了定义好的模板,又设置了自动以的模板,那么以最后一个生效</b>
     *
     * @param xTemplate 定义好的模板 {@link XTemplate}
     * @return
     */
    public XEditText setXTemplate(@NonNull XTemplate xTemplate) {
        if (null == xTemplate) return this;
        setSplitChar(mSplitChar);
        switch (xTemplate) {
            case PHONE: // 手机
                setTemplate(new int[]{3, 4, 4});
                break;
            case BANK_CARD: // 银行卡
                setTemplate(new int[]{4, 4, 4, 4, 3});
                break;
            case ID_CARD: // 身份证
                setTemplate(new int[]{4, 4, 4, 4, 2});
                break;
        }
        return this;
    }

    /**
     * 设置分割符,默认' '
     *
     * @param splitChar 需要的分隔符<br/>
     *                  <b>注意:设置EditText的输入类型的时候(设置 {@code inputType} 或 {@code digits} 属性)需要能输入分割符,
     *                  否则分割符不能输入到EditText中,那么不会对内容进行分割</b>
     * @return
     */
    public XEditText setSplitChar(@NonNull char splitChar) {
        this.mSplitChar = splitChar;
        return this;
    }

    /**
     * 设置EditText分割样式,如 {@code new int[]{3,4,4}} 表示大陆手机号码的样式,<br/>
     * <b>注意:如果设置了模板,表示已经设置的最大的长度,如果设置了模板没有设置分割符,使用默认{@code ' '}分隔符</b>
     *
     * @param template 模板样式 如:{@code new int[]{3,4,4}} 显示:132 1234 5678
     * @return
     */
    public XEditText setTemplate(@NonNull int[] template) {
        if (null == template) return this;
        int length = template.length;
        mSplitPosition = new int[length - 1];
        int temp = 0;
        for (int i = 0; i < length; i++) {
            temp += template[i];
            if (i < length - 1) {
                mSplitPosition[i] = temp;
                temp += 1;
            }
        }
        if (this.mSplitChar == ' ') {
            this.mSplitChar = DEFAULT_SPLIT;
        }
        mMaxLength = temp;
        return this;
    }

    /**
     * 设置需要格式化的文字<br/>
     * 1.调用该方法前,请先调用<code>setTemplate(@NonNull int[] template)</code>方法设置好模板或<br/>
     * 2.直接调用<code>setToTextEdit(@NonNull String text, @NonNull int[] template)</code>方法
     *
     * @param text 需要格式化的内容
     * @return
     * @see #setTemplate(int[])
     * @see #setToTextEdit(String, int[])
     */
    public XEditText setToTextEdit(@NonNull String text) {
        if (TextUtils.isEmpty(text)) {
            setText("");
            return this;
        }
        if (null == mSplitPosition || mSplitPosition.length <= 0) {
            setText(text);
            return this;
        }
        StringBuilder stringBuilder = new StringBuilder();
        int length = text.length();
        for (int i = 0; i < length; i++) {
            for (int position : mSplitPosition) {
                if (position == stringBuilder.toString().length()) stringBuilder.append(mSplitChar);
            }
            stringBuilder.append(text.charAt(i));
        }
        setText(stringBuilder.toString());
        return this;
    }

    /**
     * 指定模板设置格式化的文字,如果已经指定过模板了,可以调用<code>setToTextEdit(@NonNull String text)</code>方法<br/>
     * <b>注意:如果设置了模板没有设置分割符,使用默认{@code ' '}分隔符</b>
     *
     * @param text     需要格式化的内容
     * @param template 格式化的模板,如:{@code setToTextEdit("13212345678",new int[]{3,4,4}}) 显示:132 1234 5678
     * @return
     * @see #setTemplate(int[])
     * @see #setToTextEdit(String)
     */
    public XEditText setToTextEdit(@NonNull String text, @NonNull int[] template) {
        setTemplate(template);
        return setToTextEdit(text);
    }

    /**
     * 指定分隔符和模板设置格式化的文字,如果已经指定过模板了,可以调用<code>setToTextEdit(@NonNull String text)</code>方法<br/>
     * <b>注意:如果设置了模板没有设置分割符,使用默认{@code ' '}分隔符</b>
     *
     * @param text      需要格式化的内容
     * @param template  格式化的模板,如:{@code setToTextEdit("13212345678",new int[]{3,4,4}}) 显示:132 1234 5678
     * @param splitChar 分隔符
     * @return
     * @see #setSplitChar(char)
     * @see #setTemplate(int[])
     * @see #setToTextEdit(String)
     */
    public XEditText setToTextEdit(@NonNull String text, @NonNull int[] template, @NonNull char splitChar) {
        setSplitChar(splitChar);
        setTemplate(template);
        return setToTextEdit(text);
    }

    /**
     * 指定分隔符设置格式化的文字<br/>
     * 调用该方法前,请先调用<code>setTemplate(@NonNull int[] template)</code>方法设置好模板<br/>
     * <b>注意:如果设置了模板没有设置分割符,使用默认{@code ' '}分隔符</b>
     *
     * @param text      需要格式化的内容
     * @param splitChar 分隔符
     * @return
     * @see #setSplitChar(char)
     * @see #setTemplate(int[])
     * @see #setToTextEdit(String)
     */
    public XEditText setToTextEdit(@NonNull String text, @NonNull char splitChar) {
        setSplitChar(splitChar);
        return setToTextEdit(text);
    }

    /**
     * 设置文字改变监听
     *
     * @param onTextChangeListener
     * @return
     */
    public XEditText setOnTextChangeListener(OnTextChangeListener onTextChangeListener) {
        this.mOnTextChangeListener = onTextChangeListener;
        return this;
    }

    /**
     * 设置焦点改变监听
     *
     * @param onMyFocusChangeListener
     * @return
     */
    public XEditText setOnMyFocusChangeListener(OnMyFocusChangeListener onMyFocusChangeListener) {
        this.mOnMyFocusChangeListener = onMyFocusChangeListener;
        return this;
    }

    /**
     * 获得除去分割符的输入框内容
     */
    public String getNoSplitCharText() {
        if (TextUtils.isEmpty(mSplitChar + ""))
            return getText().toString();
        return getText().toString().replaceAll(mSplitChar + "", "");
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int eventX = (int) event.getX();
        if (mClearDrawable.isVisible() && MotionEvent.ACTION_UP == event.getAction()
                && eventX > getWidth() - getPaddingRight() - mClearDrawable.getIntrinsicHeight()) {
            setText("");
            return true;
        }
        return super.onTouchEvent(event);
    }

    /**
     * 根据是否有内容和焦点以及设置的显示状态改变右边图片的显示状态
     *
     * @param text
     * @param hasFocus
     */
    private void changeDelShowStatus(Editable text, boolean hasFocus) {
        if (DelIconShowTime.ALWAYS_SHOW == mDelIconTime) { // 总是显示
            mClearDrawable.setVisible(true, false);
        } else if (DelIconShowTime.HAS_CONTENT_SHOW == mDelIconTime) { // 有内容就显示
            if (null != text && !TextUtils.isEmpty(text.toString()))
                mClearDrawable.setVisible(true, false);
            else mClearDrawable.setVisible(false, false);
        } else if (DelIconShowTime.HAS_CONTENT_FOCUS_SHOW == mDelIconTime) { // 有内容并且有焦点时显示
            if (null != text && !TextUtils.isEmpty(text.toString()) && hasFocus)
                mClearDrawable.setVisible(true, false);
            else mClearDrawable.setVisible(false, false);
        } else { // 总是隐藏
            mClearDrawable.setVisible(false, false);
        }
        setCompoundDrawables(mCompoundDrawables[DRAWABLE_LEFT], mCompoundDrawables[DRAWABLE_TOP],
                mClearDrawable.isVisible() ? mClearDrawable : null,
                mCompoundDrawables[DRAWABLE_BOTTOM]);
    }

    /**
     * 文字改变监听
     */
    class MyTextWatcher implements TextWatcher {
        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
            mPreLength = s.length();
            if (null != mOnTextChangeListener)
                mOnTextChangeListener.beforeTextChanged(s, start, count, after);
        }

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {
            // 当没有分割符位置的时候,表示就是普通的EditText
            if (null == mSplitPosition || mSplitPosition.length == 0) {
                if (null != mOnTextChangeListener)
                    mOnTextChangeListener.onTextChanged(s, start, before, count);
                return;
            }
            // 当没有分割符的时候,表示就是普通的EditText
            if (TextUtils.isEmpty(mSplitChar + "")) {
                if (null != mOnTextChangeListener)
                    mOnTextChangeListener.onTextChanged(s, start, before, count);
                return;
            }
            mCurrentLen = s.toString().length();
            if (mCurrentLen > 0) {
                // 设置了最大值,或者设置了模板,并且已经操过了最大值,输入的值无效
                if (mMaxLength > 0 && mCurrentLen > mMaxLength) {
                    getText().delete(mCurrentLen - 1, mCurrentLen);
                    return;
                }
                for (int i = 0; i < mSplitPosition.length; i++) {
                    if (mCurrentLen == mSplitPosition[i]) {
                        if (mCurrentLen > mPreLength) {
                            // 正在增加内容
                            removeTextChangedListener(mTextWatcher);
                            mTextWatcher = null;
                            getText().insert(mCurrentLen, mSplitChar + "");
                        } else {
                            // 正在删除内容
                            removeTextChangedListener(mTextWatcher);
                            mTextWatcher = null;
                            getText().delete(mCurrentLen - 1, mCurrentLen);
                        }
                    }

                    if (mTextWatcher == null) {
                        mTextWatcher = new MyTextWatcher();
                        addTextChangedListener(mTextWatcher);
                    }
                }
            }

            if (null != mOnTextChangeListener)
                mOnTextChangeListener.onTextChanged(s, start, before, count);
        }

        @Override
        public void afterTextChanged(Editable s) {
            changeDelShowStatus(s, isFocused());
            if (null != mOnTextChangeListener)
                mOnTextChangeListener.afterTextChanged(s);
        }
    }

    /**
     * 提供给开发者调用的文字改变监听
     */
    public interface OnTextChangeListener {
        void beforeTextChanged(CharSequence s, int start, int count, int after);

        void onTextChanged(CharSequence s, int start, int before, int count);

        void afterTextChanged(Editable s);
    }

    /**
     * 提供给开发者调用的焦点改变监听
     */
    public interface OnMyFocusChangeListener {
        void onFocusChange(View view, boolean hasFocus);
    }
}

过滤器

public class EditTextFilter {
    /**
     * 最大长度
     */
    private int mMaxLength;
    /**
     * 超过最大长度时提示的消息
     */
    private String mMaxMsg;
    /**
     * 是否过滤回车键
     */
    private boolean isFilterEnter;
    /**
     * 是否过滤删除键
     */
    private boolean isFilterDel;
    /**
     * 过滤正正则表达式和相对应的提示信息
     */
    private Map<String, String> mRegMsgs;
    /**
     * EditText过滤器对象
     */
    private InputFilter mFilter;
    /**
     * 上下文
     */
    private Context mContext;

    private EditTextFilter(int maxLength, String maxMsg, boolean isFilterEnter,
                           boolean isFilterDel, Map<String, String> regMsgs) {
        this.mMaxLength = maxLength;
        this.mMaxMsg = maxMsg;
        this.isFilterEnter = isFilterEnter;
        this.isFilterDel = isFilterDel;
        this.mRegMsgs = regMsgs;
        this.mFilter = createInputFilter();
    }

    /**
     * 对 {@link EditText} 开启过滤模式
     *
     * @param editText 需要开启过滤的 {@link EditText}
     */
    public void startFilter(EditText editText) {
        if (null == editText)
            throw new NullPointerException("EditText 不能为 null");
        this.mContext = editText.getContext();
        editText.setFilters(new InputFilter[]{mFilter});
    }

    /**
     * 创建一个 {@link InputFilter} 对象
     *
     * @return {@link InputFilter} 对象
     */
    @NonNull
    private InputFilter createInputFilter() {
        return new InputFilter() {
            /**
             *
             * @param source 输入时,source为新输入的字符;删除时,source没有内容
             * @param start 输入时,一直为0;删除时,一直为0
             * @param end 输入时,表示输入字符的个数;删除时,一直为0
             * @param dest 输入时,dest为输入框中原来的字符;删除时,dest为删除前输入框中的内容
             * @param dstart 输入时,原来输入框中字符的长度;删除时,输入框中删除后字符的长度
             * @param dend 输入时,原来输入框中字符的长度;删除时,输入框中删除前字符的长度
             * @return 返回null时表示不管,让系统处理,返回 "" 表示过滤掉了
             */
            @Override
            public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
                int length = source.length();
                int length2 = dest.length();
                // 表示过滤删除
                if (isFilterDel && length == 0) {
                    return "";
                }
                // 表示过滤回车
                if (isFilterEnter && length == 1 && source.charAt(0) == 10) {
                    return "";
                }
                // 控制最大长度
                if ((mMaxLength != -1) && (length + length2 > mMaxLength)) {
                    if (!TextUtils.isEmpty(mMaxMsg))
                        Toast.makeText(mContext, mMaxMsg, Toast.LENGTH_SHORT).show();
                    return "";
                }

                // 过滤指定的正则表达式
                if (mRegMsgs.size() > 0) {
                    Set<String> strings = mRegMsgs.keySet();
                    for (String string : strings) {
                        Pattern p = Pattern.compile(string);
                        Matcher m = p.matcher(source);
                        if (m.matches()) {
                            return null;
                        } else {
                            String str = mRegMsgs.get(string);
                            if (!TextUtils.isEmpty(str) && 0 != end)
                                Toast.makeText(mContext, str, Toast.LENGTH_SHORT).show();
                            return "";
                        }
                    }
                    return null;
                } else {
                    return null;
                }
            }
        };
    }

    public static class Builder {
        private int maxLength = -1;
        private String maxMsg = null;
        private boolean isFilterEnter = false;
        private boolean isFilterDel = false;
        private Map<String, String> regMsgMap = new HashMap<>();

        /**
         * 设置最大长度
         *
         * @param maxLength 最大长度
         * @param maxMsg    超过长度时的提示信息,不需要提示时可以传 "" 或 {@code null}
         * @return
         */
        public Builder maxLength(int maxLength, String maxMsg) {
            this.maxLength = maxLength;
            this.maxMsg = maxMsg;
            return this;
        }

        /**
         * 是否过滤回车键
         *
         * @param isFilterEnter true:过滤  false:不过滤
         * @return
         */
        public Builder isFilterEnter(@NonNull boolean isFilterEnter) {
            this.isFilterEnter = isFilterEnter;
            return this;
        }

        /**
         * 是否过滤删除键
         *
         * @param isFilterDel true:过滤  false:不过滤
         * @return
         */
        public Builder isFilterDel(@NonNull boolean isFilterDel) {
            this.isFilterDel = isFilterDel;
            return this;
        }

        /**
         * 添加单个的过滤正则表达式。<br/>
         * <b>注意:</b><br/> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
         * <b>使用正则表达式过滤时,输入内容和正则表达式匹配成功的不过滤,匹配失败的将被过滤</b>
         *
         * @param reg    正则表达式
         * @param regMsg 当输入内容和正则表达式不匹配时的提示信息,不需要提示时可以传 "" 或 {@code null}
         * @return
         */
        public Builder putReg(@NonNull String reg, String regMsg) {
            regMsgMap.put(reg, regMsg);
            return this;
        }

        /**
         * 添加过滤正则表达式集合。<br/>
         * <b>注意:</b><br/> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
         * <b>使用正则表达式过滤时,输入内容和正则表达式匹配成功的不过滤,匹配失败的将被过滤</b>
         *
         * @param regMsgs 一组过滤正则表达式,map的键用正则表达式表示,值表示 不匹配时的提示信息,不需要提示时可以传 "" 或 {@code null}
         * @return
         */
        public Builder regMsgs(@NonNull Map<String, String> regMsgs) {
            this.regMsgMap.putAll(regMsgs);
            return this;
        }

        /**
         * 根据正则表达式(map集合的键)移除单个的过滤正则表达式
         *
         * @param reg
         */
        public void removeReg(@NonNull String reg) {
            this.regMsgMap.remove(reg);
        }

        /**
         * 清除所有的正则表达式过滤
         */
        public void clearReg() {
            this.regMsgMap.clear();
        }

        /**
         * 构建一个 {@link EditTextFilter} 对象
         *
         * @return {@link EditTextFilter} 对象
         */
        public EditTextFilter build() {
            return new EditTextFilter(maxLength, maxMsg, isFilterEnter, isFilterDel, regMsgMap);
        }
    }
}

<declare-styleable name="XEditText">
        <!--使用已经定义好的模板,如果既设置了原来的模板,又设置了自动以模板,以自定模板为主-->
        <attr name="x_template" format="enum">
            <enum name="phone" value="1" />
            <enum name="bank_card" value="2" />
            <enum name="id_card" value="3" />
        </attr>
        <!--定义最大长度,如果定义了模板,就不需要定义最大的长度了-->
        <attr name="maxLength" format="integer" />
        <!--定义分隔符,注意:分隔符的最大长度为1,
        如果为null,使用默认分隔符 ' ',如果长度超过1,那么取第一个位置的字符作为分割符。
        注意:设置EditText的输入类型的时候(设置 inputType 或 digits 属性)需要能输入分割符,
        否则分割符不能输入到EditText中,那么不会对内容进行分割-->
        <attr name="splitChar" format="string" />
        <!-- 定义模板,格式固定(否则无效):"第一部分长度(正整数),第二部分长度(正整数),...,第n部分长度(正整数),..."。
         比如:"3,4,4" 那么EditText显示的为 三个字符 + 分隔符 + 四个字符 + 分割符 + 四个字符-->
        <attr name="custom_template" format="string" />
        <!--指定右边清除图片-->
        <attr name="del_icon" format="reference" />
        <!--右边图片显示的时间-->
        <attr name="del_show_time" format="enum">
            <!--总是显示右边删除图片(一直显示)-->
            <enum name="always_show" value="0" />
            <!--总是隐藏右边图片(不显示)-->
            <enum name="always_hide" value="1" />
            <!--有内容时显示(不管是否有焦点)-->
            <enum name="has_content_show" value="2" />
            <!--有内容并且有焦点时显示-->
            <enum name="has_content_focus_show" value="3" />
        </attr>
</declare-styleable>

在xml文件中定义控件

<com.xedittext.edittext.XEditText
        android:id="@+id/xedit_text3"
        style="@style/style_xedittext"
        android:hint="分隔符+,模板1,2,3,4,一直显示清除图片按钮"
        renj:custom_template="1,2,3,4"
        renj:del_show_time="always_show"
        renj:splitChar="+" />

在Java代码中使用

// 在Activity中找到控件:
xEditText1 = (XEditText) findViewById(R.id.xedit_text1);

// 1.代码设置为手机号码格式,使用预定义模板形式
xEditText1.setSplitChar(' ');
//xEditText2.setSplitChar(' ');//不设置分割符,使用默认分隔符
xEditText1.setMyTemplet(XEditText.MyTemplet.PHONE);

// 2.代码设置为身份证号码格式,使用模板的形式设置
xEditText1.setTemplet(new int[]{4, 4, 4, 4, 2});

 // 3.直接将银行卡号设置到输入框1,指定模板
xEditText1.setToTextEdit("1234567890123456789", new int[]{4, 4, 4, 4, 3}, ' ');

 // 4.获取最后一个输入框去除分隔符之后的值
String splitCharText = xEditText1.getNoSplitCharText();

直接在layout.xml文件中指定模板和分隔符

<com.xedittext.edittext.XEditText
        android:id="@+id/xedit_text4"
        style="@style/style_xedittext"
        android:hint="使用预定义的手机号模板,改变分隔符为-"
        renj:x_template="phone"
        renj:splitChar="-" />


<com.xedittext.edittext.XEditText
        android:id="@+id/xedit_text3"
        style="@style/style_xedittext"
        android:hint="分隔符+,模板1,2,3,4,一直显示清除图片按钮"
        renj:custom_template="1,2,3,4"
        renj:del_show_time="always_show"
        renj:splitChar="+" />

EditText控件过滤器使用 

在xml文件中定义普通的EditText控件

<EditText
        android:id="@+id/edittext1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="12dp"
        android:hint="填写身份证号码,输入数字和Xx"
        android:digits="1234567890Xx"
        android:maxLines="1"
        android:textColor="#333666"
        android:textColorHint="#bbbbbb"
        android:textSize="14sp" />
// 找到控件
edittext1 = (EditText) findViewById(R.id.edittext1);

// 过滤身份证号码
edittext1.setKeyListener(DigitsKeyListener.getInstance(digists));
// 使用过滤器
new EditTextFilter.Builder()
        .maxLength(18, "已经达到最大长度")
        .putReg("[0123456789xX]", "请输入正确的字符")
        .build()
        .startFilter(edittext);
        
// 过滤EditText,必须是中文,最大长度为4
new EditTextFilter.Builder()
        .maxLength(4, "已经达到最大长度")
        .putReg("[\\u4e00-\\u9fa5]+", "只能输入中文")
        .build()
        .startFilter(edittext);
        
// 使用过滤器设置最大长度,提示信息
new EditTextFilter.Builder()
        .maxLength(13, "超过大陆手机号码的长度")
        .build()
        .startFilter(xedittext);

XEditText和过滤器联合使用

<com.xedittext.edittext.XEditText
        android:id="@+id/xedittext"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="8dp"
        android:hint="使用XEditText控件,输入手机号码并且过滤"
        android:inputType="phone"
        android:maxLines="1"
        android:textColor="#333666"
        android:textColorHint="#bbbbbb"
        android:textSize="14sp" />
// 找到控件
xedittext = (XEditText) findViewById(R.id.xedittext);

// 使用过滤器
// 过滤EditText,使用XEditText控件,手机号码格式,注意现在设置最大长度时必须加上分隔符的个数
xedittext.setMyTemplet(XEditText.MyTemplet.PHONE); // 设置模板
// 使用过滤器
new EditTextFilter.Builder()
        .maxLength(13, "超过大陆手机号码的长度")
        .build()
        .startFilter(xedittext);

猜你喜欢

转载自blog.csdn.net/qq_15059163/article/details/126969637