简介
在Android开发中,时不时需要用户输入一些数据,有输入就有格式上的要求。比如EditText输入金额时,通常要保留小数点后两位,这个如何实现呢?
首先在布局文件里,通过android:inputType限定EditText输入的内容,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文件
小结
方法一的实现思路和网络上搜到的实现差不多,从方法一到方法三,是一个解决问题的逻辑演变的过程。