美文网首页Android安卓 解决方案Android知识
安卓EditText-实现输入小数点后几位的逻辑演变

安卓EditText-实现输入小数点后几位的逻辑演变

作者: sugaryaruan | 来源:发表于2017-02-26 16:04 被阅读1705次

    简介

    在Android开发中,时不时需要用户输入一些数据,有输入就有格式上的要求。比如EditText输入金额时,通常要保留小数点后两位,这个如何实现呢?

    首先在布局文件里,通过android:inputType限定EditText输入的内容,numberDecimal表示只能输入带小数点的浮点格式

                    <EditText
                        android:id="@+id/tiet_invoice_free_tax_amount"
                        style="@style/InvoiceDetailEditTextStyle"
                        android:layout_width="match_parent"
                        android:layout_height="@dimen/item_invoice_detail_height"
                        android:hint="发票金额(¥):"
                        android:inputType="numberDecimal"
                     />
    

    EditText inputType属性详解 传送门

    方法一,普通实现

    给EditText添加TextChangedListener监听,重写onTextChanged方法,输入小数点后两位的逻辑

           @Override
           public void onTextChanged(CharSequence s, int start, int before,
                                      int count) {
                if (s.toString().contains(".")) {
                    if (s.length() - 1 - s.toString().indexOf(".") > 2) {
                        s = s.toString().subSequence(0,
                                s.toString().indexOf(".") + 3);
                        editText.setText(s);
                        editText.setSelection(s.length());
                    }
                }
                if (s.toString().trim().substring(0).equals(".")) {
                    s = "0" + s;
                    editText.setText(s);
                    editText.setSelection(2);
                }
    
                if (s.toString().startsWith("0")
                        && s.toString().trim().length() > 1) {
                    if (!s.toString().substring(1, 2).equals(".")) {
                        editText.setText(s.subSequence(0, 1));
                        editText.setSelection(1);
                        return;
                    }
                }
            }
    

    这种方法实现复杂,有没有更简单的?

    方法二,简洁实现

    在重写onTextChanged方法里,一旦输入的内容里包含了“.”,则限定输入的文本长度为小数点所在长度加上后两位的长度。把问题转为如何限定EditText输入的内容长度呢?EditText提供了setFilter()方法,InputFilter.LengthFilter类,实现代码如下:

    private static final int DEFAULT_MAX_INTEGER_LENGTH = 10;
    private static final int DEFAULT_DECIMAL_NUMBER = 2;
    
    private static final InputFilter[] INPUT_FILTER_ARRAY = new InputFilter[1];
    
    /**
     * 保留小数点后多少位
     */
    private int mDecimalNumber = DEFAULT_DECIMAL_NUMBER;
    /**
     * 允许最大的整数多少位
     */
    private int mMaxIntegralLength = DEFAULT_MAX_INTEGER_LENGTH;
    
    
    @Override
    protected void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) {
        super.onTextChanged(text, start, lengthBefore, lengthAfter);
        if(text.length() > 0) {
            String inputContent = text.toString();
            if (inputContent.contains(".")) {
                int maxLength = inputContent.indexOf(".") + mDecimalNumber + 1;
                INPUT_FILTER_ARRAY[0] = new InputFilter.LengthFilter(maxLength);
            } else {
                INPUT_FILTER_ARRAY[0] = new InputFilter.LengthFilter(mMaxIntegralLength);
            }
            setFilters(INPUT_FILTER_ARRAY);
        }
    }
    

    与方法一相比,方法二执行效率得到了提高,不必截取字符串长度subString,同时逻辑上也简化了

    方法三,优雅实现

    查阅InputFilter,对该类的描述:

    InputFilters can be attached to Editables to constrain the changes that can be made to them
    

    InputFilter能过滤EditText的输入内容,如此就不必监听OnTextChangeListener,而是设置过滤器的过滤逻辑,优雅得实现显示小数点后几位,核心代码如下:

    setFilters(new InputFilter[]{new InputFilter() {
            @Override
            public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
                String lastInputContent = dest.toString();
                if (lastInputContent.contains(".")) {
                    int index = lastInputContent.indexOf(".");
                    if(dend - index >= mDecimalNumber + 1){
                        return "";
                    }
                }
                return null;
            }
        }});
    

    filter方法用到的入参说明:

    • source 单次输入的字符内容
    • dest上次输入的内容

    到此,一个输入小数点后几位的自定义控件雏形已经显现了。

    二 简单的自定义控件DecimalEditText,实现输入小数点后若干位

    所有代码如下:

    public class DecimalEditText extends EditText {
    
    private static final int DEFAULT_DECIMAL_NUMBER = 2;
    /**
     * 保留小数点后多少位
     */
    private int mDecimalNumber = DEFAULT_DECIMAL_NUMBER;
    
    
    public DecimalEditText(Context context) {
        this(context,null,R.attr.editTextStyle);
    }
    
    public DecimalEditText(Context context, AttributeSet attrs) {
        this(context,attrs, R.attr.editTextStyle);
    }
    
    public DecimalEditText(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.DecimalEditText);
        mDecimalNumber = typedArray.getInt(R.styleable.DecimalEditText_decimalNumber,DEFAULT_DECIMAL_NUMBER);
        typedArray.recycle();
    
        init();
    }
    
    private void init(){
        setFilters(new InputFilter[]{new InputFilter() {
            @Override
            public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
                String lastInputContent = dest.toString();
    
                if (source.equals(".") && lastInputContent.length() == 0) {
                    return "0.";
                }
                if (lastInputContent.contains(".")) {
                    int index = lastInputContent.indexOf(".");
                    if(dend - index >= mDecimalNumber + 1){
                        return "";
                    }
                }
                return null;
            }
        }});
    }
    
    public int getDecimalNumber() {
        return mDecimalNumber;
    }
    
    public void setDecimalNumber(int decimalNumber) {
        mDecimalNumber = decimalNumber;
    }
    
    }
    

    attr文件

    <declare-styleable name="DecimalEditText">
        <attr name="decimalNumber" format="integer"/>
    </declare-styleable>
    

    小结

    方法一的实现思路和网络上搜到的实现差不多,从方法一到方法三,是一个解决问题的逻辑演变的过程。

    相关文章

      网友评论

      • KingsleyCheng:自定义的那个会有个问题,假如你限制小数点后面可以输入两位,输入0.23之后把光标移到“.”与“3”之间,这时候就还可以输入,导致限制小数点后两位失效
        sugaryaruan:这块逻辑还有很大缺陷,可以看看这篇http://blog.csdn.net/vqqyuan/article/details/44676379和https://software.intel.com/zh-cn/blogs/2013/03/07/android-edittext;
      • KingsleyCheng:写的非常好
      • cheetah747:public DecimalEditText(Context context, AttributeSet attrs) {
        this(context,attrs, R.attr.editTextStyle);
        }
        这里的this()为什么要用R.attr.editTextStyle而不是0啊?看别的自定义组件好像都是用的0.。。。。然后我自己试了下自定义EditText好像也必须像你这么写才行,否则就会点击不了,获取不了焦点。。。为啥???一头雾水。。
        sugaryaruan:@cheetah747 这么说也对:smile:
        cheetah747:@sugaryaruan 哦,就是说TextView之类的这种比较特殊?然后一般情况下的自定义组件都是传0就好了吧?
        sugaryaruan:当时在做的时候,也是出了问题,然后看了下View,ViewGroup,TextView源码的构造方法,特别是TextView两个参数的(Context context,AtributeSet)的构造方法,发现,TextView的构造方法,需要传的是R.attr.editTextStyle,因此DecimalTextView这里不能传0
      • 李福来:非常不错
        李福来:@sugaryaruan 项目中在用了,多谢!
        sugaryaruan:@李福来 😀
      • Aldrich_N:这个不错

      本文标题:安卓EditText-实现输入小数点后几位的逻辑演变

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