Reputation: 605
The requirement is to limit user from not entering more than 1 decimal value in a numeric/decimal edit text field. That said, I also need to limit the number entry to 6 Max digits. eg. 999999.9
If a user enters numeric alone - then I should be able to limit the user to 6 digits Max, but should allow "." and decimal number(if entered by the user).
I am not sure, how to do this. Any help and reference will be of great help.
Upvotes: 1
Views: 3856
Reputation: 739
There is a small mistake in above answer
I edited that one use the below code.
import java.math.RoundingMode;
import java.text.NumberFormat;
import android.text.Editable;
import android.text.TextWatcher;
import android.widget.EditText;
public class DecimalTextWatcher implements TextWatcher {
private NumberFormat numberFormat = NumberFormat.getNumberInstance();
private EditText editText;
private String temp = "";
private int moveCaretTo;
private int integerConstraint;
private int fractionConstraint;
private int maxLength;
/**
* Add a text watcher to Edit text for decimal formats
*
* @param editText
* EditText to add DecimalTextWatcher
* @param before
* digits before decimal point
* @param after
* digits after decimal point
*/
public DecimalTextWatcher(EditText editText, int before, int after) {
this.editText = editText;
this.integerConstraint = before;
this.fractionConstraint = after;
this.maxLength = before + after + 1;
numberFormat.setMaximumIntegerDigits(integerConstraint);
numberFormat.setMaximumFractionDigits(fractionConstraint);
numberFormat.setRoundingMode(RoundingMode.DOWN);
numberFormat.setGroupingUsed(false);
}
private int countOccurrences(String str, char c) {
int count = 0;
for (int i = 0; i < str.length(); i++) {
if (str.charAt(i) == c) {
count++;
}
}
return count;
}
@Override
public void afterTextChanged(Editable s) {
// remove to prevent StackOverFlowException
editText.removeTextChangedListener(this);
String ss = s.toString();
int len = ss.length();
int dots = countOccurrences(ss, '.');
boolean shouldParse = dots <= 1 && (dots == 0 ? len != (integerConstraint + 1) : len < (maxLength + 1));
boolean x = false;
if (dots == 1) {
int indexOf = ss.indexOf('.');
try {
if (ss.charAt(indexOf + 1) == '0') {
shouldParse = false;
x = true;
if (ss.substring(indexOf).length() > 2) {
shouldParse = true;
x = false;
}
}
} catch (Exception ex) {
}
}
if (shouldParse) {
if (len > 1 && ss.lastIndexOf(".") != len - 1) {
try {
Double d = Double.parseDouble(ss);
if (d != null) {
editText.setText(numberFormat.format(d));
}
} catch (NumberFormatException e) {
}
}
} else {
if (x) {
editText.setText(ss);
} else {
editText.setText(temp);
}
}
editText.addTextChangedListener(this); // reset listener
// tried to fix caret positioning after key type:
if (editText.getText().toString().length() > 0) {
if (dots == 0 && len >= integerConstraint && moveCaretTo > integerConstraint) {
moveCaretTo = integerConstraint;
} else if (dots > 0 && len >= (maxLength) && moveCaretTo > (maxLength)) {
moveCaretTo = maxLength;
}
try {
editText.setSelection(editText.getText().toString().length());
// et.setSelection(moveCaretTo); <- almost had it :))
} catch (Exception e) {
}
}
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
moveCaretTo = editText.getSelectionEnd();
temp = s.toString();
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
int length = editText.getText().toString().length();
if (length > 0) {
moveCaretTo = start + count - before;
}
}
}
use it as below..
itemCostEditText.addTextChangedListener(new DecimalTextWatcher(itemCostEditText, 6, 2));
Upvotes: 2
Reputation: 4718
Maybe some implementation similar to this? I'm pretty sure it can be optimized a lot!
EditText et;
.....
// force number input type on edittext
et.setRawInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_DECIMAL);
et.addTextChangedListener(new CustomTextWatcher(et));
where:
class CustomTextWatcher implements TextWatcher {
private NumberFormat nf = NumberFormat.getNumberInstance();
private EditText et;
private String tmp = "";
private int moveCaretTo;
private static final int INTEGER_CONSTRAINT = 6;
private static final int FRACTION_CONSTRAINT = 1;
private static final int MAX_LENGTH = INTEGER_CONSTRAINT + FRACTION_CONSTRAINT + 1;
public CustomTextWatcher(EditText et) {
this.et = et;
nf.setMaximumIntegerDigits(INTEGER_CONSTRAINT);
nf.setMaximumFractionDigits(FRACTION_CONSTRAINT);
nf.setGroupingUsed(false);
}
public int countOccurrences(String str, char c) {
int count = 0;
for (int i = 0; i < str.length(); i++) {
if (str.charAt(i) == c) {
count++;
}
}
return count;
}
@Override
public void afterTextChanged(Editable s) {
et.removeTextChangedListener(this); // remove to prevent stackoverflow
String ss = s.toString();
int len = ss.length();
int dots = countOccurrences(ss, '.');
boolean shouldParse = dots <= 1 && (dots == 0 ? len != (INTEGER_CONSTRAINT + 1) : len < (MAX_LENGTH + 1));
if (shouldParse) {
if (len > 1 && ss.lastIndexOf(".") != len - 1) {
try {
Double d = Double.parseDouble(ss);
if (d != null) {
et.setText(nf.format(d));
}
} catch (NumberFormatException e) {
}
}
} else {
et.setText(tmp);
}
et.addTextChangedListener(this); // reset listener
//tried to fix caret positioning after key type:
if (et.getText().toString().length() > 0) {
if (dots == 0 && len >= INTEGER_CONSTRAINT && moveCaretTo > INTEGER_CONSTRAINT) {
moveCaretTo = INTEGER_CONSTRAINT;
} else if (dots > 0 && len >= (MAX_LENGTH) && moveCaretTo > (MAX_LENGTH)) {
moveCaretTo = MAX_LENGTH;
}
try {
et.setSelection(et.getText().toString().length());
// et.setSelection(moveCaretTo); <- almost had it :))
} catch (Exception e) {
}
}
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
moveCaretTo = et.getSelectionEnd();
tmp = s.toString();
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
int length = et.getText().toString().length();
if (length > 0) {
moveCaretTo = start + count - before;
}
}
}
Not 100% but you can use as a base and build on top of it ;)
EDIT: tried to polishing setting the caret position after text changed but it was more difficult than I estimated and reverted to setting the caret at the end after each char input. I left the code I started on for the caret maybe you can improve it?
Upvotes: 4
Reputation: 10309
You can make use of TextWatcher's afterTextChanged/onTextChanged methods to get notified for text changes and DecimalFormat to format input text
http://developer.android.com/reference/java/text/DecimalFormat.html
http://developer.android.com/reference/android/text/TextWatcher.html
Upvotes: 0