我正在尝试编写一个帮助你管理财务的应用程序。我使用了一个EditText
字段,用户可以在其中指定金额。
我将inputType
设置为numberDecimal
,这很好用,但是这允许人们输入像123.122
这样不适合货币的数字。
有没有办法限制小数点后的数字位数为两位?
我正在尝试编写一个帮助你管理财务的应用程序。我使用了一个EditText
字段,用户可以在其中指定金额。
我将inputType
设置为numberDecimal
,这很好用,但是这允许人们输入像123.122
这样不适合货币的数字。
有没有办法限制小数点后的数字位数为两位?
更优雅的方法是使用正则表达式(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)});
不使用正则表达式的更简单解决方案:
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)});
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);
}
}
这是一个示例InputFilter,它只允许小数点前最多4位数字,小数点后最多1位数字。
EditText允许的值:555.2,555,.2
EditText阻止的值:55555.2,055.2,555.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 });
我不喜欢其他解决方案,所以我创建了自己的解决方案。 使用这个解决方案,在小数点前面不能输入超过MAX_BEFORE_POINT位数字,在小数点后面的小数位数也不能超过MAX_DECIMAL。
你只需要输入正确数量的数字,没有其他影响! 另外,如果你输入 "." ,它会自动变成"0."。
Set the EditText in the layout to:
android:inputType="numberDecimal"
Add the Listener in your onCreate. If you want modify the number of digits before and after the point edit the call to PerfectDecimal(str, NUMBER_BEFORE_POINT, NUMBER_DECIMALS), here is set to 3 and 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());
}
}
});
Include this Funcion:
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;
}
完成了!
if(up > MAX_BEFORE_POINT) return rFinal;
这段代码。有一种情况是,如果你回到 EditText 的开头并开始输入,它将在 MAX_BEFORE_POINT 个字符后发生。这会删除之前存在的小数位。 - Tsuharesu我对@Pinhassi的解决方案进行了修正。它处理了以下情况:
1.您可以将光标移动到任何位置
2.负号处理
3.digitsbefore = 2且digitsafter = 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 "";
}
}
android:inputType="number"
或 android:inputType="numberDecimal"
,它将不允许输入负号,而 android:digits="0123456789.-"
也无法解决此问题。 - user924android:inputType ="numbersigned"
,现在我可以输入负号,但是我无法输入小数点 .
!android:digits="0123456789."
也没有帮助! - user924android:digits="0123456789.-"
和 android:inputType="numberDecimal|numberSigned"
! - user924TextWatcher
实现了这一点。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 count = -1;
- Gunaseelan我设计的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)});
要求小数点后有2位数字,小数点前的数字没有限制。因此,解决方案应为:
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()});
感谢@Pinhassi的启发。
我的解决方案简单且完美地运作!
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));
isValid()
移动到构造函数中,以避免在每次 isValid()
调用时重新创建模式。 - Hemant Kaushik
InputFilter
接口,它似乎可以满足我的需求http://developer.android.com/reference/android/text/method/NumberKeyListener.html#filter%28java.lang.CharSequence,%20int,%20int,%20android.text.Spanned,%20int,%20int%29,但是我需要实现的`filter`方法对我来说相当困惑。是否已经有人编写了这样的过滤器并知道如何使用它? - Konstantin Weitz