在 Android EditText 中限制小数位数

我在写一个应用程序帮你管理财务。我使用的是 EditText字段,用户可以在其中指定一个金额。

我将 inputType设置为 numberDecimal,这个设置很好,除了这个设置允许人们输入诸如 123.122这样的数字,这对于钱来说并不完美。

有没有办法将小数点后的字符数限制为两个?

138937 次浏览

在将字符串放入 TextView 之前,请尝试使用 GetCurrencyInstance ()格式化字符串。

比如:

NumberFormat currency = NumberFormat.getCurrencyInstance();
myTextView.setText(currency.format(dollars));

编辑 -在文档中找不到货币的 inputType。我想这是因为有些货币在小数点后不遵循同样的规则,比如日元。

正如 LeffelMania 所提到的,您可以通过使用上面的代码修正用户输入,并在 EditText上设置 TextWatcher

这个 InputFilter的实现解决了这个问题。

import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.method.DigitsKeyListener;


public class MoneyValueFilter extends DigitsKeyListener {
public MoneyValueFilter() {
super(false, true);
}


private int digits = 2;


public void setDigits(int d) {
digits = d;
}


@Override
public CharSequence filter(CharSequence source, int start, int end,
Spanned dest, int dstart, int dend) {
CharSequence out = super.filter(source, start, end, dest, dstart, dend);


// if changed, replace the source
if (out != null) {
source = out;
start = 0;
end = out.length();
}


int len = end - start;


// if deleting, source is empty
// and deleting can't break anything
if (len == 0) {
return source;
}


int dlen = dest.length();


// Find the position of the decimal .
for (int i = 0; i < dstart; i++) {
if (dest.charAt(i) == '.') {
// being here means, that a number has
// been inserted after the dot
// check if the amount of digits is right
return (dlen-(i+1) + len > digits) ?
"" :
new SpannableStringBuilder(source, start, end);
}
}


for (int i = start; i < end; ++i) {
if (source.charAt(i) == '.') {
// being here means, dot has been inserted
// check if the amount of digits is right
if ((dlen-dend) + (end-(i + 1)) > digits)
return "";
else
break;  // return new SpannableStringBuilder(source, start, end);
}
}


// if the dot is after the inserted part,
// nothing can break
return new SpannableStringBuilder(source, start, end);
}
}

不使用正则表达式的更简单的解决方案:

import android.text.InputFilter;
import android.text.Spanned;


/**
* Input filter that limits the number of decimal digits that are allowed to be
* entered.
*/
public class DecimalDigitsInputFilter implements InputFilter {


private final int decimalDigits;


/**
* Constructor.
*
* @param decimalDigits maximum decimal digits
*/
public DecimalDigitsInputFilter(int decimalDigits) {
this.decimalDigits = decimalDigits;
}


@Override
public CharSequence filter(CharSequence source,
int start,
int end,
Spanned dest,
int dstart,
int dend) {




int dotPos = -1;
int len = dest.length();
for (int i = 0; i < len; i++) {
char c = dest.charAt(i);
if (c == '.' || c == ',') {
dotPos = i;
break;
}
}
if (dotPos >= 0) {


// protects against many dots
if (source.equals(".") || source.equals(","))
{
return "";
}
// if the text is entered before the dot
if (dend <= dotPos) {
return null;
}
if (len - dotPos > decimalDigits) {
return "";
}
}


return null;
}


}

使用方法:

editText.setFilters(new InputFilter[] {new DecimalDigitsInputFilter(2)});

更优雅的方法是使用正则表达式(regex) ,如下所示:

public class DecimalDigitsInputFilter implements InputFilter {


Pattern mPattern;


public DecimalDigitsInputFilter(int digitsBeforeZero,int digitsAfterZero) {
mPattern=Pattern.compile("[0-9]{0," + (digitsBeforeZero-1) + "}+((\\.[0-9]{0," + (digitsAfterZero-1) + "})?)||(\\.)?");
}


@Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {


Matcher matcher=mPattern.matcher(dest);
if(!matcher.matches())
return "";
return null;
}


}

使用它可以:

editText.setFilters(new InputFilter[] {new DecimalDigitsInputFilter(5,2)});
DecimalFormat form = new DecimalFormat("#.##", new DecimalFormatSymbols(Locale.US));
EditText et;
et.setOnEditorActionListener(new TextView.OnEditorActionListener() {
@Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {


if (actionId == EditorInfo.IME_ACTION_DONE) {
double a = Double.parseDouble(et.getText().toString());
et.setText(form.format(a));
}
return false;
}
});

这样做的目的是,当您退出编辑阶段时,它将字段格式化为正确的格式。在他们的时刻,它只有2个小数字符。我觉得这个方法很简单。

略有改进的@Pinassi 解决方案。

非常有效,它验证连接的字符串。

public class DecimalDigitsInputFilter implements InputFilter {


Pattern mPattern;


public DecimalDigitsInputFilter() {
mPattern = Pattern.compile("([1-9]{1}[0-9]{0,2}([0-9]{3})*(\\.[0-9]{0,2})?|[1-9]{1}[0-9]{0,}(\\.[0-9]{0,2})?|0(\\.[0-9]{0,2})?|(\\.[0-9]{1,2})?)");


}


@Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {


String formatedSource = source.subSequence(start, end).toString();


String destPrefix = dest.subSequence(0, dstart).toString();


String destSuffix = dest.subSequence(dend, dest.length()).toString();


String result = destPrefix + formatedSource + destSuffix;


result = result.replace(",", ".");


Matcher matcher = mPattern.matcher(result);


if (matcher.matches()) {
return null;
}


return "";
}


}

我的解决办法是:

     yourEditText.addTextChangedListener(new TextWatcher() {
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
NumberFormat formatter = new DecimalFormat("#.##");
double doubleVal = Double.parseDouble(s.toString());
yourEditText.setText(formatter.format(doubleVal));
}


@Override
public void beforeTextChanged(CharSequence s, int start, int count,int after) {}


@Override
public void afterTextChanged(Editable s) {}
});

如果用户在小数点后面输入一个多于两个数字的数字,它将被自动更正。

希望我帮上忙了!

我通过以下方法在 TextWatcher的帮助下实现了这一点

final EditText et = (EditText) findViewById(R.id.EditText1);
int count = -1;
et.addTextChangedListener(new TextWatcher() {
public void onTextChanged(CharSequence arg0, int arg1, int arg2,int arg3) {


}
public void beforeTextChanged(CharSequence arg0, int arg1,int arg2, int arg3) {


}


public void afterTextChanged(Editable arg0) {
if (arg0.length() > 0) {
String str = et.getText().toString();
et.setOnKeyListener(new OnKeyListener() {
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_DEL) {
count--;
InputFilter[] fArray = new InputFilter[1];
fArray[0] = new InputFilter.LengthFilter(100);
et.setFilters(fArray);
//change the edittext's maximum length to 100.
//If we didn't change this the edittext's maximum length will
//be number of digits we previously entered.
}
return false;
}
});
char t = str.charAt(arg0.length() - 1);
if (t == '.') {
count = 0;
}
if (count >= 0) {
if (count == 2) {
InputFilter[] fArray = new InputFilter[1];
fArray[0] = new InputFilter.LengthFilter(arg0.length());
et.setFilters(fArray);
//prevent the edittext from accessing digits
//by setting maximum length as total number of digits we typed till now.
}
count++;
}
}
}
});

此解决方案不允许用户在小数点后输入超过两位数字。你也可以在小数点之前输入任意数字。希望这个能帮上忙。谢谢你。

这里所有的答案都很复杂,我试着让它变得更简单。看看我的代码,然后自己决定

int temp  = 0;
int check = 0;


editText.addTextChangedListener(new TextWatcher() {


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


if(editText.getText().toString().length()<temp)
{
if(!editText.getText().toString().contains("."))
editText.setFilters(new InputFilter[] { new InputFilter.LengthFilter(editText.getText().toString().length()-1) });
else
editText.setFilters(new InputFilter[] { new InputFilter.LengthFilter(editText.getText().toString().length()+1) });


}


if(!editText.getText().toString().contains("."))
{
editText.setFilters(new InputFilter[] { new InputFilter.LengthFilter(editText.getText().toString().length()+1) });
check=0;
}




else if(check==0)
{
check=1;
editText.setFilters(new InputFilter[] { new InputFilter.LengthFilter(editText.getText().toString().length()+2) });
}
}


@Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
temp = editText.getText().toString().length();




}


@Override
public void afterTextChanged(Editable s) {
// TODO Auto-generated method stub


}
});

我也遇到过这个问题。我希望能够在许多 EditText 中重用这些代码。这是我的解决办法:

用法:

CurrencyFormat watcher = new CurrencyFormat();
priceEditText.addTextChangedListener(watcher);

班级:

public static class CurrencyFormat implements TextWatcher {


public void onTextChanged(CharSequence arg0, int start, int arg2,int arg3) {}


public void beforeTextChanged(CharSequence arg0, int start,int arg2, int arg3) {}


public void afterTextChanged(Editable arg0) {
int length = arg0.length();
if(length>0){
if(nrOfDecimal(arg0.toString())>2)
arg0.delete(length-1, length);
}


}




private int nrOfDecimal(String nr){
int len = nr.length();
int pos = len;
for(int i=0 ; i<len; i++){
if(nr.charAt(i)=='.'){
pos=i+1;
break;
}
}
return len-pos;
}
}

我非常喜欢平哈西的回答,但是注意到当用户在小数点后面输入了指定的数字后,你就不能再在小数点左边输入文本了。问题在于,该解决方案只测试以前输入的文本,而不测试目前输入的文本。因此,我的解决方案是将新字符插入原始文本以进行验证。

package com.test.test;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


import android.text.InputFilter;
import android.text.Spanned;
import android.util.Log;


public class InputFilterCurrency implements InputFilter {
Pattern moPattern;


public InputFilterCurrency(int aiMinorUnits) {
// http://www.regexplanet.com/advanced/java/index.html
moPattern=Pattern.compile("[0-9]*+((\\.[0-9]{0,"+ aiMinorUnits + "})?)||(\\.)?");


} // InputFilterCurrency


@Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
String lsStart  = "";
String lsInsert = "";
String lsEnd    = "";
String lsText   = "";


Log.d("debug", moPattern.toString());
Log.d("debug", "source: " + source + ", start: " + start + ", end:" + end + ", dest: " + dest + ", dstart: " + dstart + ", dend: " + dend );


lsText = dest.toString();


// If the length is greater then 0, then insert the new character
// into the original text for validation
if (lsText.length() > 0) {


lsStart = lsText.substring(0, dstart);
Log.d("debug", "lsStart : " + lsStart);
// Check to see if they have deleted a character
if (source != "") {
lsInsert = source.toString();
Log.d("debug", "lsInsert: " + lsInsert);
} // if
lsEnd = lsText.substring(dend);
Log.d("debug", "lsEnd   : " + lsEnd);
lsText = lsStart + lsInsert + lsEnd;
Log.d("debug", "lsText  : " + lsText);


} // if


Matcher loMatcher = moPattern.matcher(lsText);
Log.d("debug", "loMatcher.matches(): " + loMatcher.matches() + ", lsText: " + lsText);
if(!loMatcher.matches()) {
return "";
}
return null;


} // CharSequence


} // InputFilterCurrency

以及设置 edit Text 筛选器的调用

editText.setFilters(new InputFilter[] {new InputFilterCurrency(2)});


Ouput with two decimal places
05-22 15:25:33.434: D/debug(30524): [0-9]*+((\.[0-9]{0,2})?)||(\.)?
05-22 15:25:33.434: D/debug(30524): source: 5, start: 0, end:1, dest: 123.4, dstart: 5, dend: 5
05-22 15:25:33.434: D/debug(30524): lsStart : 123.4
05-22 15:25:33.434: D/debug(30524): lsInsert: 5
05-22 15:25:33.434: D/debug(30524): lsEnd   :
05-22 15:25:33.434: D/debug(30524): lsText  : 123.45
05-22 15:25:33.434: D/debug(30524): loMatcher.matches(): true, lsText: 123.45


Ouput inserting a 5 in the middle
05-22 15:26:17.624: D/debug(30524): [0-9]*+((\.[0-9]{0,2})?)||(\.)?
05-22 15:26:17.624: D/debug(30524): source: 5, start: 0, end:1, dest: 123.45, dstart: 2, dend: 2
05-22 15:26:17.624: D/debug(30524): lsStart : 12
05-22 15:26:17.624: D/debug(30524): lsInsert: 5
05-22 15:26:17.624: D/debug(30524): lsEnd   : 3.45
05-22 15:26:17.624: D/debug(30524): lsText  : 1253.45
05-22 15:26:17.624: D/debug(30524): loMatcher.matches(): true, lsText: 1253.45

我的解决方案很简单,效果完美!

public class DecimalInputTextWatcher implements TextWatcher {


private String mPreviousValue;
private int mCursorPosition;
private boolean mRestoringPreviousValueFlag;
private int mDigitsAfterZero;
private EditText mEditText;


public DecimalInputTextWatcher(EditText editText, int digitsAfterZero) {
mDigitsAfterZero = digitsAfterZero;
mEditText = editText;
mPreviousValue = "";
mRestoringPreviousValueFlag = false;
}


@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
if (!mRestoringPreviousValueFlag) {
mPreviousValue = s.toString();
mCursorPosition = mEditText.getSelectionStart();
}
}


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


@Override
public void afterTextChanged(Editable s) {
if (!mRestoringPreviousValueFlag) {


if (!isValid(s.toString())) {
mRestoringPreviousValueFlag = true;
restorePreviousValue();
}


} else {
mRestoringPreviousValueFlag = false;
}
}


private void restorePreviousValue() {
mEditText.setText(mPreviousValue);
mEditText.setSelection(mCursorPosition);
}


private boolean isValid(String s) {
Pattern patternWithDot = Pattern.compile("[0-9]*((\\.[0-9]{0," + mDigitsAfterZero + "})?)||(\\.)?");
Pattern patternWithComma = Pattern.compile("[0-9]*((,[0-9]{0," + mDigitsAfterZero + "})?)||(,)?");


Matcher matcherDot = patternWithDot.matcher(s);
Matcher matcherComa = patternWithComma.matcher(s);


return matcherDot.matches() || matcherComa.matches();
}
}

用法:

myTextEdit.addTextChangedListener(new DecimalInputTextWatcher(myTextEdit, 2));

我不喜欢另一个解决方案,我自己创造了一个。 使用此解决方案,您不能在点之前输入超过 MAX _ BEFORE _ POINT 数字,小数不能超过 MAX _ DECIMAL。

你只是不能输入过多的数字,没有其他的影响! 另外,如果你写“。”它键入“0。”

  1. 将布局中的 EditText 设置为:

    InputType = “ numberDecimal”

  2. 在 onCreate 中添加监听器。如果希望在点之前和之后修改对 PerfectDecimal (str,NUMBER _ BEFORE _ POINT,NUMBER _ DECIMALS)的调用,这里设置为3和2

    EditText targetEditText = (EditText)findViewById(R.id.targetEditTextLayoutId);
    
    
    targetEditText.addTextChangedListener(new TextWatcher() {
    public void onTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {}
    
    
    public void beforeTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {}
    
    
    public void afterTextChanged(Editable arg0) {
    String str = targetEditText.getText().toString();
    if (str.isEmpty()) return;
    String str2 = PerfectDecimal(str, 3, 2);
    
    
    if (!str2.equals(str)) {
    targetEditText.setText(str2);
    targetEditText.setSelection(str2.length());
    }
    }
    });
    
  3. 包括以下功能:

    public String PerfectDecimal(String str, int MAX_BEFORE_POINT, int MAX_DECIMAL){
    if(str.charAt(0) == '.') str = "0"+str;
    int max = str.length();
    
    
    String rFinal = "";
    boolean after = false;
    int i = 0, up = 0, decimal = 0; char t;
    while(i < max){
    t = str.charAt(i);
    if(t != '.' && after == false){
    up++;
    if(up > MAX_BEFORE_POINT) return rFinal;
    }else if(t == '.'){
    after = true;
    }else{
    decimal++;
    if(decimal > MAX_DECIMAL)
    return rFinal;
    }
    rFinal = rFinal + t;
    i++;
    }return rFinal;
    }
    

搞定了!

我为@Pinhasi 解决方案做了一些修改,它可以处理一些情况:

你可以在任何地方移动光标

2. 减去标志处理

3.之前的数字 = 2,之后的数字 = 4,然后输入12.4545。然后,如果你想删除“,它将不允许。

public class DecimalDigitsInputFilter implements InputFilter {
private int mDigitsBeforeZero;
private int mDigitsAfterZero;
private Pattern mPattern;


private static final int DIGITS_BEFORE_ZERO_DEFAULT = 100;
private static final int DIGITS_AFTER_ZERO_DEFAULT = 100;


public DecimalDigitsInputFilter(Integer digitsBeforeZero, Integer digitsAfterZero) {
this.mDigitsBeforeZero = (digitsBeforeZero != null ? digitsBeforeZero : DIGITS_BEFORE_ZERO_DEFAULT);
this.mDigitsAfterZero = (digitsAfterZero != null ? digitsAfterZero : DIGITS_AFTER_ZERO_DEFAULT);
mPattern = Pattern.compile("-?[0-9]{0," + (mDigitsBeforeZero) + "}+((\\.[0-9]{0," + (mDigitsAfterZero)
+ "})?)||(\\.)?");
}


@Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
String replacement = source.subSequence(start, end).toString();
String newVal = dest.subSequence(0, dstart).toString() + replacement
+ dest.subSequence(dend, dest.length()).toString();
Matcher matcher = mPattern.matcher(newVal);
if (matcher.matches())
return null;


if (TextUtils.isEmpty(source))
return dest.subSequence(dstart, dend);
else
return "";
}
}

我改进了解决方案,使用一个正则表达式的 Pinhasi,所以它也处理边缘情况正确。在检查输入是否正确之前,首先按照 android 文档的描述构造最终的字符串。

public class DecimalDigitsInputFilter implements InputFilter {


private Pattern mPattern;


private static final Pattern mFormatPattern = Pattern.compile("\\d+\\.\\d+");


public DecimalDigitsInputFilter(int digitsBeforeDecimal, int digitsAfterDecimal) {
mPattern = Pattern.compile(
"^\\d{0," + digitsBeforeDecimal + "}([\\.,](\\d{0," + digitsAfterDecimal +
"})?)?$");
}


@Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest,
int dstart, int dend) {


String newString =
dest.toString().substring(0, dstart) + source.toString().substring(start, end)
+ dest.toString().substring(dend, dest.toString().length());


Matcher matcher = mPattern.matcher(newString);
if (!matcher.matches()) {
return "";
}
return null;
}
}

用法:

editText.setFilters(new InputFilter[] {new DecimalDigitsInputFilter(5,2)});

@ Meh for u.

txtlist.setFilters(new InputFilter[] { new DigitsKeyListener( Boolean.FALSE,Boolean.TRUE) {


int beforeDecimal = 7;
int afterDecimal = 2;


@Override
public CharSequence filter(CharSequence source, int start, int end,Spanned dest, int dstart, int dend) {


String etText = txtlist.getText().toString();
String temp = txtlist.getText() + source.toString();
if (temp.equals(".")) {
return "0.";
} else if (temp.toString().indexOf(".") == -1) {
// no decimal point placed yet
if (temp.length() > beforeDecimal) {
return "";
}
} else {
int dotPosition ;
int cursorPositon = txtlistprice.getSelectionStart();
if (etText.indexOf(".") == -1) {
dotPosition = temp.indexOf(".");
}else{
dotPosition = etText.indexOf(".");
}
if(cursorPositon <= dotPosition){
String beforeDot = etText.substring(0, dotPosition);
if(beforeDot.length()<beforeDecimal){
return source;
}else{
if(source.toString().equalsIgnoreCase(".")){
return source;
}else{
return "";
}
}
}else{
temp = temp.substring(temp.indexOf(".") + 1);
if (temp.length() > afterDecimal) {
return "";
}
}
}
return super.filter(source, start, end, dest, dstart, dend);
}
} });

这里是一个样本 输入过滤器,它只允许最大4位小数点之前和最大1位之后。

编辑文本允许的值: 555.2555

编辑文本阻塞的值: 5555.2055.2555.42

        InputFilter filter = new InputFilter() {
final int maxDigitsBeforeDecimalPoint=4;
final int maxDigitsAfterDecimalPoint=1;


@Override
public CharSequence filter(CharSequence source, int start, int end,
Spanned dest, int dstart, int dend) {
StringBuilder builder = new StringBuilder(dest);
builder.replace(dstart, dend, source
.subSequence(start, end).toString());
if (!builder.toString().matches(
"(([1-9]{1})([0-9]{0,"+(maxDigitsBeforeDecimalPoint-1)+"})?)?(\\.[0-9]{0,"+maxDigitsAfterDecimalPoint+"})?"


)) {
if(source.length()==0)
return dest.subSequence(dstart, dend);
return "";
}


return null;


}
};


mEdittext.setFilters(new InputFilter[] { filter });

这是将小数点后的位数限制为两位的最简单解决方案:

myeditText2 = (EditText) findViewById(R.id.editText2);
myeditText2.setInputType(3);
et = (EditText) vw.findViewById(R.id.tx_edittext);


et.setFilters(new InputFilter[] {
new DigitsKeyListener(Boolean.FALSE, Boolean.TRUE) {
int beforeDecimal = 5, afterDecimal = 2;


@Override
public CharSequence filter(CharSequence source, int start, int end,
Spanned dest, int dstart, int dend) {
String temp = et.getText() + source.toString();


if (temp.equals(".")) {
return "0.";
}
else if (temp.toString().indexOf(".") == -1) {
// no decimal point placed yet
if (temp.length() > beforeDecimal) {
return "";
}
} else {
temp = temp.substring(temp.indexOf(".") + 1);
if (temp.length() > afterDecimal) {
return "";
}
}


return super.filter(source, start, end, dest, dstart, dend);
}
}
});

这对我来说没问题。它允许在焦点改变和检索回来之后输入值。例如: 123.0012.120.01等。.

1. Integer.parseInt(getString(R.string.valuelength)) 指定从 string.xml文件访问的输入 digits.Values的长度。很容易更改值。 2. Integer.parseInt(getString(R.string.valuedecimal)),这是小数点后位数的最大限制。

private InputFilter[] valDecimalPlaces;
private ArrayList<EditText> edittextArray;


valDecimalPlaces = new InputFilter[] { new DecimalDigitsInputFilterNew(
Integer.parseInt(getString(R.string.valuelength)),
Integer.parseInt(getString(R.string.valuedecimal)))
};

允许执行操作的 EditText值的数组。

for (EditText etDecimalPlace : edittextArray) {
etDecimalPlace.setFilters(valDecimalPlaces);

我只是使用了包含多个编辑文本的值数组 下一个 DecimalDigitsInputFilterNew.class文件。

import android.text.InputFilter;
import android.text.Spanned;


public class DecimalDigitsInputFilterNew implements InputFilter {


private final int decimalDigits;
private final int before;


public DecimalDigitsInputFilterNew(int before ,int decimalDigits) {
this.decimalDigits = decimalDigits;
this.before = before;
}


@Override
public CharSequence filter(CharSequence source, int start, int end,
Spanned dest, int dstart, int dend) {
StringBuilder builder = new StringBuilder(dest);
builder.replace(dstart, dend, source
.subSequence(start, end).toString());
if (!builder.toString().matches("(([0-9]{1})([0-9]{0,"+(before-1)+"})?)?(\\.[0-9]{0,"+decimalDigits+"})?")) {
if(source.length()==0)
return dest.subSequence(dstart, dend);
return "";
}
return null;
}
}

要求是 小数后两位数。小数点前的数字应该是 没有限制。因此,解决方案应该是,

public class DecimalDigitsInputFilter implements InputFilter {


Pattern mPattern;


public DecimalDigitsInputFilter() {
mPattern = Pattern.compile("[0-9]*+((\\.[0-9]?)?)||(\\.)?");
}


@Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
Matcher matcher = mPattern.matcher(dest);
if (!matcher.matches())
return "";
return null;
}
}

把它当做,

mEditText.setFilters(new InputFilter[]{new DecimalDigitsInputFilter()});

感谢@Pinassi 给我的灵感。

Here is the TextWatcher that allow only N number of digits after decimal point.

TextWatcher

private static boolean flag;
public static TextWatcher getTextWatcherAllowAfterDeci(final int allowAfterDecimal){


TextWatcher watcher = new TextWatcher() {


@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
// TODO Auto-generated method stub


}


@Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
// TODO Auto-generated method stub


}


@Override
public void afterTextChanged(Editable s) {
// TODO Auto-generated method stub
String str = s.toString();
int index = str.indexOf ( "." );
if(index>=0){
if((index+1)<str.length()){
String numberD = str.substring(index+1);
if (numberD.length()!=allowAfterDecimal) {
flag=true;
}else{
flag=false;
}
}else{
flag = false;
}
}else{
flag=false;
}
if(flag)
s.delete(s.length() - 1,
s.length());
}
};
return watcher;
}

怎么用

yourEditText.addTextChangedListener(getTextWatcherAllowAfterDeci(1));

我已经修改了上面的解决方案,并创建了以下一个。您可以设置小数点前后的位数。

public class DecimalDigitsInputFilter implements InputFilter {


private final Pattern mPattern;


public DecimalDigitsInputFilter(int digitsBeforeZero, int digitsAfterZero) {
mPattern = Pattern.compile(String.format("[0-9]{0,%d}(\\.[0-9]{0,%d})?", digitsBeforeZero, digitsAfterZero));
}


@Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
Matcher matcher = mPattern.matcher(createResultString(source, start, end, dest, dstart, dend));
if (!matcher.matches())
return "";
return null;
}


private String createResultString(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
String sourceString = source.toString();
String destString = dest.toString();
return destString.substring(0, dstart) + sourceString.substring(start, end) + destString.substring(dend);
}

}

这里的 Simple Helper 类是为了防止用户在小数点后输入超过2位数字:

public class CostFormatter  implements TextWatcher {


private final EditText costEditText;


public CostFormatter(EditText costEditText) {
this.costEditText = costEditText;
}


@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 synchronized void afterTextChanged(final Editable text) {
String cost = text.toString().trim();


if(!cost.endsWith(".") && cost.contains(".")){
String numberBeforeDecimal = cost.split("\\.")[0];
String numberAfterDecimal = cost.split("\\.")[1];


if(numberAfterDecimal.length() > 2){
numberAfterDecimal = numberAfterDecimal.substring(0, 2);
}
cost = numberBeforeDecimal + "." + numberAfterDecimal;
}
costEditText.removeTextChangedListener(this);
costEditText.setText(cost);
costEditText.setSelection(costEditText.getText().toString().trim().length());
costEditText.addTextChangedListener(this);
}
}

一个非常晚的回答: 我们可以这样做:

etv.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) {
if (s.toString().length() > 3 && s.toString().contains(".")) {
if (s.toString().length() - s.toString().indexOf(".") > 3) {
etv.setText(s.toString().substring(0, s.length() - 1));
etv.setSelection(edtSendMoney.getText().length());
}
}
}


@Override
public void afterTextChanged(Editable arg0) {
}
}

这是建立在平哈西的答案之上的——我遇到的问题是,一旦达到小数极限,就不能在小数之前添加值。为了解决这个问题,我们需要在进行模式匹配之前构造最后一个字符串。

import java.util.regex.Matcher;
import java.util.regex.Pattern;


import android.text.InputFilter;
import android.text.Spanned;


public class DecimalLimiter implements InputFilter
{
Pattern mPattern;


public DecimalLimiter(int digitsBeforeZero,int digitsAfterZero)
{
mPattern=Pattern.compile("[0-9]{0," + (digitsBeforeZero) + "}+((\\.[0-9]{0," + (digitsAfterZero) + "})?)||(\\.)?");
}


@Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend)
{
StringBuilder sb = new StringBuilder(dest);
sb.insert(dstart, source, start, end);


Matcher matcher = mPattern.matcher(sb.toString());
if(!matcher.matches())
return "";
return null;
}
}

实现这一目标的最简单方法是:

et.addTextChangedListener(new TextWatcher() {
public void onTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {
String text = arg0.toString();
if (text.contains(".") && text.substring(text.indexOf(".") + 1).length() > 2) {
et.setText(text.substring(0, text.length() - 1));
et.setSelection(et.getText().length());
}
}


public void beforeTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {


}


public void afterTextChanged(Editable arg0) {
}
});

我已经改变了答案6号(由法瓦斯 Kv) ,因为在那里你可以把只是点在第一个位置。

final InputFilter [] filter = { new InputFilter() {


@Override
public CharSequence filter(CharSequence source, int start, int end,
Spanned dest, int dstart, int dend) {
StringBuilder builder = new StringBuilder(dest);
builder.replace(dstart, dend, source
.subSequence(start, end).toString());
if (!builder.toString().matches(
"(([1-9]{1})([0-9]{0,4})?(\\.)?)?([0-9]{0,2})?"


)) {
if(source.length()==0)
return dest.subSequence(dstart, dend);
return "";
}
return null;
}
}};

正如其他人所说,我在我的项目中添加了这个类,并将过滤器设置为我想要的 EditText

过滤器是从@Pixel 的答案中复制过来的,我只是把它们放在一起。

public class DecimalDigitsInputFilter implements InputFilter {


Pattern mPattern;


public DecimalDigitsInputFilter() {
mPattern = Pattern.compile("([1-9]{1}[0-9]{0,2}([0-9]{3})*(\\.[0-9]{0,2})?|[1-9]{1}[0-9]{0,}(\\.[0-9]{0,2})?|0(\\.[0-9]{0,2})?|(\\.[0-9]{1,2})?)");


}


@Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {


String formatedSource = source.subSequence(start, end).toString();


String destPrefix = dest.subSequence(0, dstart).toString();


String destSuffix = dest.subSequence(dend, dest.length()).toString();


String result = destPrefix + formatedSource + destSuffix;


result = result.replace(",", ".");


Matcher matcher = mPattern.matcher(result);


if (matcher.matches()) {
return null;
}


return "";
}
}

现在像这样设置 EditText中的过滤器。

mEditText.setFilters(new InputFilter[]{new DecimalDigitsInputFilter()});

这里一个重要的事情是,它确实解决了我的问题,不允许显示超过两个数字后的小数点,该 EditText,但问题是,当我 getText()从该 EditText,它返回我输入的整个输入。

例如,在 EditText上应用过滤器之后,我尝试将输入设置为1.5699856987。所以在屏幕上显示1.56,这是完美的。

然后,我希望将这个输入用于其他一些计算,因此我希望从该输入字段(EditText)获得文本。当我调用 mEditText.getText().toString()时,它返回1.5699856987,这在我的情况下是不可接受的。

因此,我必须在从 EditText获取值之后再次解析该值。

BigDecimal amount = new BigDecimal(Double.parseDouble(mEditText.getText().toString().trim()))
.setScale(2, RoundingMode.HALF_UP);

setScale在从 EditText获得完整的文本之后在这里起作用。

我提出的 InputFilter 允许您配置小数位前后的位数。此外,它不允许前导零。

public class DecimalDigitsInputFilter implements InputFilter
{
Pattern pattern;


public DecimalDigitsInputFilter(int digitsBeforeDecimal, int digitsAfterDecimal)
{
pattern = Pattern.compile("(([1-9]{1}[0-9]{0," + (digitsBeforeDecimal - 1) + "})?||[0]{1})((\\.[0-9]{0," + digitsAfterDecimal + "})?)||(\\.)?");
}


@Override public CharSequence filter(CharSequence source, int sourceStart, int sourceEnd, Spanned destination, int destinationStart, int destinationEnd)
{
// Remove the string out of destination that is to be replaced.
String newString = destination.toString().substring(0, destinationStart) + destination.toString().substring(destinationEnd, destination.toString().length());


// Add the new string in.
newString = newString.substring(0, destinationStart) + source.toString() + newString.substring(destinationStart, newString.length());


// Now check if the new string is valid.
Matcher matcher = pattern.matcher(newString);


if(matcher.matches())
{
// Returning null indicates that the input is valid.
return null;
}


// Returning the empty string indicates the input is invalid.
return "";
}
}


// To use this InputFilter, attach it to your EditText like so:
final EditText editText = (EditText) findViewById(R.id.editText);


EditText.setFilters(new InputFilter[]{new DecimalDigitsInputFilter(4, 4)});
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
String numero = total.getText().toString();
int dec = numero.indexOf(".");
int longitud = numero.length();
if (dec+3 == longitud && dec != -1) { //3 number decimal + 1
log.i("ento","si");
numero = numero.substring(0,dec+3);
if (contador == 0) {
contador = 1;
total.setText(numero);
total.setSelection(numero.length());
} else {
contador = 0;
}
}
}

这个代码运行良好,

public class DecimalDigitsInputFilter implements InputFilter {


private final int digitsBeforeZero;
private final int digitsAfterZero;
private Pattern mPattern;


public DecimalDigitsInputFilter(int digitsBeforeZero, int digitsAfterZero) {
this.digitsBeforeZero = digitsBeforeZero;
this.digitsAfterZero = digitsAfterZero;
applyPattern(digitsBeforeZero, digitsAfterZero);
}


private void applyPattern(int digitsBeforeZero, int digitsAfterZero) {
mPattern = Pattern.compile("[0-9]{0," + (digitsBeforeZero - 1) + "}+((\\.[0-9]{0," + (digitsAfterZero - 1) + "})?)|(\\.)?");
}


@Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
if (dest.toString().contains(".") || source.toString().contains("."))
applyPattern(digitsBeforeZero + 2, digitsAfterZero);
else
applyPattern(digitsBeforeZero, digitsAfterZero);


Matcher matcher = mPattern.matcher(dest);
if (!matcher.matches())
return "";
return null;
}


}

应用过滤器:

edittext.setFilters(new InputFilter[] {new DecimalDigitsInputFilter(5,2)});

正如其他人所说,我在我的项目中添加了这个类,并在不使用 regex 的情况下将过滤器设置为 EditText Simpler 解决方案:

public class DecimalDigitsInputFilter implements InputFilter {
int digitsBeforeZero =0;
int digitsAfterZero=0;


public DecimalDigitsInputFilter(int digitsBeforeZero,int digitsAfterZero) {
this.digitsBeforeZero=digitsBeforeZero;
this.digitsAfterZero=digitsAfterZero;
}


@Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
if(dest!=null && dest.toString().trim().length()<(digitsBeforeZero+digitsAfterZero)){
String value=dest.toString().trim();
if(value.contains(".") && (value.substring(value.indexOf(".")).length()<(digitsAfterZero+1))){
return ((value.indexOf(".")+1+digitsAfterZero)>dstart)?null:"";
}else if(value.contains(".") && (value.indexOf(".")<dstart)){
return "";
}else if(source!=null && source.equals(".")&& ((value.length()-dstart)>=(digitsAfterZero+1))){
return "";
}


}else{
return "";
}
return null;
}

}

应用过滤器:

edittext.setFilters(new InputFilter[] {new DecimalDigitsInputFilter(5,2)});

在 Android kotlin 中创建一个名为 DecimalDigitsInputFilter 的新类

class DecimalDigitsInputFilter(digitsBeforeDecimal: Int, digitsAfterDecimal: Int) : InputFilter {


var mPattern: Pattern = Pattern.compile("[0-9]{0,$digitsBeforeDecimal}+((\\.[0-9]{0,$digitsAfterDecimal})?)||(\\.)?")


override fun filter(
source: CharSequence?,
start: Int,
end: Int,
dest: Spanned?,
dstart: Int,
dend: Int
): CharSequence? {
val matcher: Matcher = mPattern.matcher(
dest?.subSequence(0, dstart).toString() + source?.subSequence(
start,
end
).toString() + dest?.subSequence(dend, dest.length).toString()
)
if (!matcher.matches())
return ""
else
return null
}
}

使用以下代码行调用此类

 et_buy_amount.filters = (arrayOf<InputFilter>(DecimalDigitsInputFilter(8,2)))

有太多的答案相同,但它将允许您输入8位前小数和2位后小数

其他答案只接受8位数字

没有正则表达式的简单解决方案

    int start=Edit1.getSelectionStart();
String sp=Edit1.getText().toString();
sp=sp.replace(",",".");
Double d=Double.valueOf(sp);
String s=String.format("%.2f",d );
if(!Edit1.getText().toString().equals(s))
Edit1.setText(s);
if(start>Edit1.getText().length())start--;
Edit1.setSelection(start);

通过删除逗号,由于数字变成了一个整数,所以零变成了两个。

为了科特林

val inputFilter =  arrayOf<InputFilter>(DecimalDigitsInputFilter(5,2))
et_total_value.setFilters(inputFilter)

这个 InputFilter 的实现解决了这个问题。

import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.method.DigitsKeyListener;


public class MoneyValueFilter extends DigitsKeyListener {
public MoneyValueFilter() {
super(false, true);
}


private int digits = 2;


public void setDigits(int d) {
digits = d;
}


@Override
public CharSequence filter(CharSequence source, int start, int end,
Spanned dest, int dstart, int dend) {
CharSequence out = super.filter(source, start, end, dest, dstart, dend);


// if changed, replace the source
if (out != null) {
source = out;
start = 0;
end = out.length();
}


int len = end - start;


// if deleting, source is empty
// and deleting can't break anything
if (len == 0) {
return source;
}


int dlen = dest.length();


// Find the position of the decimal .
for (int i = 0; i < dstart; i++) {
if (dest.charAt(i) == '.') {
// being here means, that a number has
// been inserted after the dot
// check if the amount of digits is right
return (dlen-(i+1) + len > digits) ?
"" :
new SpannableStringBuilder(source, start, end);
}
}


for (int i = start; i < end; ++i) {
if (source.charAt(i) == '.') {
// being here means, dot has been inserted
// check if the amount of digits is right
if ((dlen-dend) + (end-(i + 1)) > digits)
return "";
else
break;  // return new SpannableStringBuilder(source, start, end);
}
}


// if the dot is after the inserted part,
// nothing can break
return new SpannableStringBuilder(source, start, end);
}
}

使用方法:

editCoin.setFilters(new InputFilter[] {new MoneyValueFilter(2)});

返回文章页面简单绑定适配器在 Kotlin:

@BindingAdapter("maxDecimalPlaces")
fun TextInputEditText.limitDecimalPlaces(maxDecimalPlaces: Int) {
filters += InputFilter { source, _, _, dest, dstart, dend ->
val value = if (source.isEmpty()) {
dest.removeRange(dstart, dend)
} else {
StringBuilder(dest).insert(dstart, source)
}
val matcher = Pattern.compile("([1-9][0-9]*)|([1-9][0-9]*\\.[0-9]{0,$maxDecimalPlaces})|(\\.[0-9]{0,$maxDecimalPlaces})").matcher(value)
if (!matcher.matches()) "" else null
}
}

如果要对整数部分有限制,这里还有代码

class PropertyCostInputFilter : DigitsKeyListener(false, true) {


override fun filter(source: CharSequence, start: Int, end: Int, dest: Spanned, dstart: Int, dend: Int): CharSequence {
var source = source
var start = start
var end = end
val out = super.filter(source, start, end, dest, dstart, dend)


if (out != null) {
source = out
start = 0
end = out.length
}


val sourceLength = end - start


// If length = 0, then there was a deletion and therefore the length could not become greater than the max value
if (sourceLength == 0) {
return source
}


val result = dest.replaceRange((dstart until dend), source.substring(start, end))
val parts = result.split(SEPARATOR)


if (parts.size > 0 && parts[0].length > INTEGER_PART_MAX_DIGITS
|| parts.size > 1 && parts[1].length > FRACTIONAL_PART_MAX_DIGITS
) {
return ""
}


return SpannableStringBuilder(source, start, end)
}


companion object {
private const val INTEGER_PART_MAX_DIGITS = 20
private const val FRACTIONAL_PART_MAX_DIGITS = 2
private const val SEPARATOR = '.'
}
}

如果有 maxDigitsBeforeDecimalPoint 或 maxDigitsAfterDecimalPoint 这样的限制,则可以在 class 下面使用。

public class DecimalDigitsInputFilter implements InputFilter {
@Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
StringBuilder builder = new StringBuilder(dest);
int maxDigitsBeforeDecimalPoint = 6;
int maxDigitsAfterDecimalPoint = 2;
builder.replace(dstart, dend, source
.subSequence(start, end).toString());
if (!builder.toString().matches(
"(([1-9]{1})([0-9]{0," + (maxDigitsBeforeDecimalPoint - 1) + "})?)?(\\.[0-9]{0," + maxDigitsAfterDecimalPoint + "})?"


)) {
if (source.length() == 0)
return dest.subSequence(dstart, dend);
return "";
}


return null;
}

}

对我来说,我需要在小数点前最大6位,在小数点后最大2位,所以我声明了变量,如 int maxDigitsBefore DecimalPoint = 6; Int maxDigitsAfterDecimalPoint = 2; 可以根据需要使用。

用法

editText.setFilters(new InputFilter[]{new DecimalDigitsInputFilter()});

希望对你也有帮助。