eddy eddy - 5 months ago 16
Java Question

Android - How to only allow a certain number of decimal places

Do you know of any method to make sure users can only enter figures with a maximum number of decimals.
I'm not sure how to address this problem. In the MS SQL database I'm going to send data from my app I've got columns with this type

decimal(8,3)

Now considering the data type of the column that's finally going to store the value I want to validate in Android, I've considered these two cases:


  1. If the user enters a number with no decimals, the maximum number of digits must be 8

  2. If the user enters a number with decimals, the maximum number of digits must be 8 (including the digits to the right of the decimal point)



Now I'm sure about the first case, but not so much about the second. Is it right to keep the number of maximum digits fixed(for example, always 8)? Or should I consider allowing a maximum of 8 digits to the left and 3 to the right of the decimal point?

Either way this is what I've been trying in Android:

mQuantityEditText.addTextChangedListener(new TextWatcher() {
@Override
public void afterTextChanged(Editable s) {
String str = mQuantityEditText.getText().toString();
DecimalFormat format = (DecimalFormat) DecimalFormat
.getInstance();
DecimalFormatSymbols symbols = format.getDecimalFormatSymbols();
char sep = symbols.getDecimalSeparator();

int indexOFdec = str.indexOf(sep);

if (indexOFdec >= 0) {
if (str.substring(indexOFdec, str.length() - 1).length() > 3) {
s.replace(0, s.length(),
str.substring(0, str.length() - 1));
}
}
}

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

}

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

}
});


Even though, the above code handles the maximum number of decimal places. It does not limit the total number of digits allowed in the EditText.

Do you think you could help me improve my code so that it handles both the maximum number of decimal places and the total number of digits allowed in a EditText (considering both numbers to the left and to the right of the decimal point)

EDIT



Well, now I'm trying what João Sousa suggested and here's what I've tried:

1) I defined a class that implements InputFilter

public class NumberInputFilter implements InputFilter {
private Pattern mPattern;

public NumberInputFilter(int precision, int scale) {
String pattern="^\\-?(\\d{0," + (precision-scale) + "}|\\d{0," + (precision-scale) + "}\\.\\d{0," + scale + "})$";
this.mPattern=Pattern.compile(pattern);

}

@Override
public CharSequence filter(CharSequence source, int start, int end, Spanned destination, int destinationStart, int destinationEnd) {
if (end > start) {
// adding: filter
// build the resulting text
String destinationString = destination.toString();
String resultingTxt = destinationString.substring(0, destinationStart) + source.subSequence(start, end) + destinationString.substring(destinationEnd);
// return null to accept the input or empty to reject it
return resultingTxt.matches(this.mPattern.toString()) ? null : "";
}
// removing: always accept
return null;
}

}


2) Tried to use the class like this :

mQuantityEditText.setFilters(new InputFilter[] { new NumberInputFilter(8,3)} );

Answer

I would go for a filter in the edit text itself with the power of regex. First the regex expression:

^\-?(\d{0,5}|\d{0,5}\.\d{0,3})$

Maybe there are multiple ways to improve this expression, but this does trick.

And now just set an input filter in the edittext, like this:

final String regex = "^\-?(\d{0,5}|\d{0,5}\.\d{0,3})$";
((EditText)rootView.findViewById(R.id.editText1)).setFilters(new InputFilter[] {
    new InputFilter() {
        @Override
        public CharSequence filter(CharSequence source, int start, int end, Spanned destination, int destinationStart, int destinationEnd) {
            if (end > start) {
                // adding: filter   
                // build the resulting text
                String destinationString = destination.toString();
                String resultingTxt = destinationString.substring(0, destinationStart) + source.subSequence(start, end) + destinationString.substring(destinationEnd);
                // return null to accept the input or empty to reject it
                return resultingTxt.matches(regex) ? null : "";
            }
            // removing: always accept
            return null;
        }
    }
});

Btw, I just tested this code and what it does is:

  1. The user can enter a maximum of 8 digits;
  2. As soon as the user enters a '.', the maximum decimal digits allowed are 8.

Did I correctly understand the problem you described?

-- EDIT

Ok, I was almost there. From what I understand, decimal(8,3) means at most 8 digits including digits to the left or right of the decimal point, ranging from -99999.999 to 99999.999. At least that's what I understand from this sentence Standard SQL requires that DECIMAL(5,2) be able to store any value with five digits and two decimals, so values that can be stored in the salary column range from -999.99 to 999.99. Even though it's from the MySQL documentation the MSSQL docs seem to do the same.