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

我的简书博客 sugaryaruan 传送门

简介

在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的输入内容,如此就不必监听OnTextChangeLister,而是设置过滤器的过滤逻辑,优雅得实现显示小数点后几位,核心代码如下:

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 DecimalTextInputEditText(Context context) {
    this(context,null,R.attr.editTextStyle);
}

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

public DecimalTextInputEditText(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>

小结

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值