需求背景
很多时候,我们需要实现一个输入金额或者数量的小数数字输入框,要求限制小数最多输入2位,即需要限制整数和小数输入位数。
解决方案
解决办法一般有两种
-
设置textWatcher,监听输入,如果输入不满足格式要求,则对结果进行处理,重新setText()进行赋值。如下伪代码:
editText.addTextWatcher(new TextWatcher{ ... afterTextChanged(Editable s){ //如果输入“.”则自动变为“0.” if (".".equals(s.toString())){ editText.setText("0."); } //判断小数点位置,并对长度进行判断拦截 ... } })textWatcher的缺点在于:
(1)当对输入内容进行了校验和修改后,需要重新持有EditText对象进行setText()。
(2)另外如果不注意使用,在AdapterView中很容易重复设置textWatcher。
所以此处更推荐使用InputFilter
-
设置InputFilter,对输入直接进行处理。
网络搜索一番,如下是一个比较流行的解决方案:
stackoverflow.com/questions/3…
但是这个方案有个很严重的bug:当小数位数达到上限时,无法编辑整数位;整数位数达到上限时,也无法编辑小数位。
基于这个方案,进行了改进,有了下文的方案:
先设置了目标正则公式
"[0-9]{0,digitsBeforeZero}+(\\.[0-9]{0,digitsAfterZero})?"
(1)简单解析一下这个正则公式:
[0-9]{0,digitsBeforeZero}+ 表示有0-digitsBeforeZero个0-9的整数;
(\.[0-9]{0,digitsAfterZero})? 表示有0-digitsAfterZero个0-9的小数,小数可有可无。
也就是说,123,123.1,123.12都是符合条件的。
(2)然后对输入进行处理,得到结果值。
如果符合正则公式,则输入成功;如果不符合正则公式,则不允许输入。
public class DecimalDigitsInputFilter implements InputFilter {
Pattern mPattern;
public DecimalDigitsInputFilter(int digitsBeforeZero, int digitsAfterZero) {
String regex = String.format("[0-9]{0,%d}+(\\.[0-9]{0,%d})?", digitsBeforeZero, digitsAfterZero);
mPattern = Pattern.compile(regex);
}
@Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
//直接输入"."返回"0."
//".x"删除"x"输出为".",inputFilter无法处理成"0.",所以只处理直接输入"."的case
if (".".equals(source) && "".equals(dest.toString())) {
return "0.";
}
StringBuilder builder = new StringBuilder(dest);
if ("".equals(source)) {
builder.replace(dstart, dend, "");
} else {
builder.insert(dstart, source);
}
String resultTemp = builder.toString();
//判断修改后的数字是否满足小数格式,不满足则返回 "",不允许修改
Matcher matcher = mPattern.matcher(resultTemp);
if (!matcher.matches()) {
return "";
}
return null;
}
}