Reputation: 1279
Well my requirement is to add filters in an edit text in such a manner that it can contain maximum value upto 6 digits and 2 digits after the decimal point.Well what I basically need is to allow users to input 6 digits at most and 2 digits after the decimal point at most .
For example
999999.99 is valid (6 digits and two digits after the decimal)
9999999 is not valid (& digits)
999.99 is valid (3 digits and 2 digits after the decimal place)
Now after googling for a while I found a solution to my problem with the following piece of code using TextWatcher
public static CharSequence validText ="";
public static EditText setAmountValidation(final EditText editText,final Context context){
editText.addTextChangedListener(new TextWatcher()
{
private final Pattern sPattern = Pattern.compile("^([1-9][0-9]{0,5})?(\\.[0-9]{0,2}?)?$");
private CharSequence mText="";
private boolean isValid(CharSequence s) {
return sPattern.matcher(s).matches();
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count){
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after){
if(isValid(s)){
validText= s;
}
mText = isValid(s) ? s : validText;
}
@Override
public void afterTextChanged(Editable s)
{
if (!isValid(s))
{
editText.setText(mText);
}
mText = "";
}
});
return editText;
}
}
Now the code above throws the following error
Java stackoverflowerror
What is it that I am missing ?
Upvotes: 2
Views: 943
Reputation: 44
If you want to allow only 6 digits before decimal and 2 digits after decimal you no need to add addTextChangedListener
if you want only 8 digit (either
beforeDecimal = 6, afterDecimal = 2 (or) beforeDecimal = 8, afterDecimal = 0 you can use addTextChangedListener
.
EditText tv;
tv = (EditText) findViewById(R.id.test_value);
int beforeDecimal = 6, afterDecimal = 2;
tv.setFilters(new InputFilter[] { new DigitsKeyListener(Boolean.FALSE,
Boolean.TRUE) {
@Override
public CharSequence filter(CharSequence source, int start, int end,
Spanned dest, int dstart, int dend) {
String etText = tv.getText().toString();
if (etText.isEmpty()) {
return null;
}
String temp = tv.getText() + source.toString();
if (temp.equals(".")) {
return "0.";
} else if (temp.toString().indexOf(".") == -1) {
if (temp.length() > beforeDecimal) {
return "";
}
} else {
int dotPosition;
int cursorPositon = tv.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);
}
} });
tv.addTextChangedListener(new TextWatcher() {
public void onTextChanged(CharSequence s, int start, int before,
int count) {
String temp = tv.getText() + s.toString();
if (temp.contains(".")) {
beforeDecimal = 6; /***6 Digits beforedecimal and 2 after decimal****/
afterDecimal = 2;
} else {
beforeDecimal = 8; /***8 Digits beforedecimal and 0 after decimal***/
afterDecimal = 0;
}
}
Upvotes: 0
Reputation: 11321
I think your problem is that you are trying to set the EditText again in your public void afterTextChanged(Editable s)
for the case inputs are not valid.
if you change text in afterTextChanged then another afterTextChanged will be called over and over again like you can see in logcat
See also documentation for afterTextChanged they do warn about possible creation of infinite loops there:
This method is called to notify you that, somewhere within s, the text has been changed. It is legitimate to make further changes to s from this callback, but be careful not to get yourself into an infinite loop, because any changes you make will cause this method to be called again recursively
Upvotes: 1