天天看點

自定義EditTextView 限定數字格式和最大值

/**
 * 自定義EditTextView   限定數字格式和最大值
 */
public class FormatEditText extends androidx.appcompat.widget.AppCompatEditText{

    private static final int UN_DEFINED = Integer.MAX_VALUE;

    private static final int INTEGER = 0;
    private static final int FLOAT = 1;
    private static final int TEXT = 2;
    private int dotNum = 2;//小數點數量
    private int maxValue;
    private int customInputType;

    public FormatEditText(Context context){
        super(context);
    }

    public FormatEditText(Context context, AttributeSet attrs){
        super(context, attrs);
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.FormatEditText);
        maxValue = typedArray.getInt(R.styleable.FormatEditText_value_max, UN_DEFINED);
        customInputType = typedArray.getInt(R.styleable.FormatEditText_value_format, TEXT);
        dotNum = typedArray.getInt(R.styleable.FormatEditText_value_dot, 2);
        initEditText();
        typedArray.recycle();
    }

    private void initEditText(){
        if(customInputType == TEXT){
            return;
        }else if(customInputType == INTEGER){
            setInputType(InputType.TYPE_CLASS_NUMBER);
            Log.e("customInputType", "INTEGER");
            setIntegerFilter();
        }else if(customInputType == FLOAT){
            setInputType(InputType.TYPE_NUMBER_FLAG_DECIMAL);
            setFloatFilter();
            Log.e("customInputType", "FLOAT");
        }
    }

    /**
     * 去掉整數前面的0
     */
    private String cutInt(String text){
        if(text.length() > 1 && text.startsWith("0")){
            text = text.substring(1);
            return cutInt(text);
        }
        return text;
    }

    private void setIntegerFilter(){
        addTextChangedListener(new TextWatcher(){
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after){
            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count){
            }

            @Override
            public void afterTextChanged(Editable s){
                String trim = s.toString().trim();
                if(!TextUtils.isEmpty(trim) && trim.length() > 1 && trim.startsWith("0")){
                    String text = cutInt(trim);
                    setText(text);
                    setSelection(text.length());
                }else if(maxValue != UN_DEFINED && !TextUtils.isEmpty(trim) && trim.length() > 0){
                    try{
                        int value = Integer.parseInt(trim);
                        if(value > maxValue){
                            App.showMessage(getContext().getString(R.string.max_value_notice) + maxValue);
                            String substring = trim.substring(0, trim.length() - 1);
                            setText(substring);
                            setSelection(substring.length());
                        }
                    }catch(Exception e){
                        e.printStackTrace();
                    }
                }
            }
        });
    }

    private void setFloatFilter(){
        setFilters(new InputFilter[]{new FloatFilter(dotNum, maxValue)});
        addTextChangedListener(new TextWatcher(){
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after){
            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count){
            }

            @Override
            public void afterTextChanged(Editable s){
                String trim = s.toString().trim();
                if(!TextUtils.isEmpty(trim) && trim.length() > 1 && trim.startsWith("0") && !trim.startsWith("0.")){
                    String text = cutInt(trim);
                    setText(text);
                    setSelection(text.length());
                }else if(!TextUtils.isEmpty(trim) && trim.length() > 0 && trim.startsWith(".")){
                    String newText = "0" + trim;
                    setText(newText);
                    setSelection(newText.length());
                }
            }
        });
    }

    public class FloatFilter implements InputFilter{
        Pattern mPattern;
        float max;

        /**
         * @param digitsAfterZero 保留幾位小數
         * @param max    最大值
         */
        int length = 6;     //小數點前面整數位數

        public FloatFilter(int digitsAfterZero, float max){
            String regex = String.format("[0-9]{0,%d}+(\\.[0-9]{0,%d})?", length, digitsAfterZero);
            mPattern = Pattern.compile(regex);
            this.max = max;
        }

        /**
         * dest  輸入前的文字
         * source  輸入的文字
         */
        @Override
        public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend){
            //直接輸入"."傳回"0."
            //            Log.e("dest", dest.toString() + "   __");
            if(".".equals(source.toString()) && "".equals(dest.toString())){
                return "0.";
            }
            StringBuilder builder = new StringBuilder(dest);
            builder.insert(dstart, source);
            String resultTemp = builder.toString();
            //判斷修改後的數字是否滿足小數格式,不滿足則傳回 "",不允許修改
            Matcher matcher = mPattern.matcher(resultTemp);
            if(!matcher.matches()){
                return "";
            }
            if(max != UN_DEFINED && resultTemp.length() > 0){
                try{
                    float value = Float.parseFloat(resultTemp);
                    if(value > max){
                        App.showMessage(getContext().getString(R.string.max_value_notice) + max);
                        return "";
                    }
                }catch(Exception e){
                    return "";
                }
            }
            return source;
        }
    }
}
           
<?xml version="1.0" encoding="utf-8"?>
<resources>
 <declare-styleable name="FormatEditText">
<!--        <attr name="value_min" format="integer" />-->
        <attr name="value_max" format="integer" />
        <attr name="value_dot" format="integer" />
        <attr name="value_format">
            <enum name="v_integer" value="0" />
            <enum name="v_float" value="1" />
            <enum name="v_text" value="2" />
        </attr>
    </declare-styleable>
</resources>