This question already has answers here:
Is there a way to define a min and max value for EditText in Android?
(29 answers)
Closed 11 months ago.
I am creating an app that calculates the the users marks. How do I go forward, I'm trying to limit the user's input value to between min=0 and max=100?
I've got 3 inputs that I want to limit.
EditText a = (EditText) findViewById(R.id.Assignment1);
EditText b = (EditText) findViewById(R.id.Assignment2);
EditText c = (EditText) findViewById(R.id.Assignment3);
Tried using the following but only works when I execute my function.
public void YearMark(View v)
{
EditText a = (EditText) findViewById(R.id.Assignment1);
a.setFilters(new InputFilter[]{ new InputFilterMinMax("0", "100")});
As #JAY_Panchal mentioned, you can use an InputFilter:
public class RangeInputFilter implements InputFilter {
private final int min, max;
public RangeInputFilter(int min, int max) {
boolean rightOrder = min <= max;
this.min = rightOrder ? min : max;
this.max = rightOrder ? max : min;
}
#Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dStart, int dEnd) {
try {
String sourceStr = source.toString();
String destStr = dest.toString();
String result = destStr.substring(0, dStart) + sourceStr.substring(start, end) + destStr.substring(dEnd);
int input = Integer.parseInt(result);
if (min <= input && input <= max) return null;
} catch (NumberFormatException ignored) { }
return "";
}
}
When a user changes the content of an EditText, you can use an InputFilter to decide what actually changes in the EditText.
Returning null means that the input is accepted.
Returning something else (in this case "") means that source should be replaced with that (in this case, we want dest to stay as it is and thus have an empty source).
To assign your filter:
RangeInputFilter filter = new RangeInputFilter(0, 100);
InputFilter[] filters = new InputFilter[] {filter};
editText1.setFilters(filters);
editText2.setFilters(filters);
editText3.setFilters(filters);
Add this textwatcher for all three edittext a,b and c:
a.addTextChangedListener(new TextWatcher() {
#Override
public void afterTextChanged(Editable s) {
}
#Override
public void beforeTextChanged(CharSequence s, int start,
int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start,
int before, int count) {
String strTest = editText1235.getText().toString().trim();
if (!strTest.equals("")) {
float no = Float.parseFloat(strTest);
if (no > 100) {
a.setText(null);
Toast.makeText(this, "enter a value less than 100", Toast.LENGTH_SHORT).show();
}
}
}
});
Also set input type of these text fields as number so that user cannot enter a negative sign,ie, any value less than 0.
android:inputType="number"
While submitting the details also check if the field is not empty like below:
if (a.getText().toString().trim().length() <=0 ||b.getText().toString().trim().length() <=0 ||c.getText().toString().trim().length() <= 0){
Toast.makeText(this, "Value cannot be empty", Toast.LENGTH_SHORT).show();
}
I don't know your usecase, but you might also want to use a SeekBar.
A SeekBar is a slider - you can select a number by sliding. It is also very customizable.
The main advantage is that the user does not need to open the keyboard.
Related
I'm making an application that can control weight (kilogram).
I have an edittext that can accept enter decimal numbers using:
et_beratbadan.setInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_DECIMAL | InputType.TYPE_NUMBER_FLAG_SIGNED);
my edittext already able to limit entering numbers, 3 digits before zero and 1 digit after zero (120.1) using:
et_beratbadan.setFilters(new InputFilter[]{new DecimalDigitsInputFilter(3, 1)});
what i want is, my edittext able to limit entering numbers, 3 digits before zero and 1 digit after zero, not accept minus values and start from one.
so it would allow : 123.4, 12.3, 1.2
not allow : 0, -12.3, 0.1
i already try code from https://stackoverflow.com/a/38793820 to make my edittext do not accept minus value. and some other code, that i lost the link for it.
and i have a class for implement inputfilter:
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 "";
}
}
sorry I'm still learning English and java. thanks!
I have an editText that is set so that a user can only enter an integer value. The value is then sent to an API. The problem is that the server get's overloaded if the value is too high (Heroku problems).
I was wondering if there was a way to actually limit the value that was able to be entered into the editText. For example the user can only enter a value between 1-800.
Obvioulsy I cant limit the value by number of figures, for example 3 figures, as that would allow for a value of up to 999.
There is another question open for this, however the answers in that Q dont seem to come up with one elegant solution, instead an amalgamation of different pieces of buggy code.
Here is the current MainActivity and xml for the editText.
activity_main.xml
<EditText
android:id="#+id/editText2"
android:layout_width="274dp"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="278dp"
android:ems="10"
android:hint="Enter number of tweets..."
android:inputType="number" />
mainActivity.Java
EditText editText2 = findViewById(R.id.editText2);
String tweetNo = editText2.getText().toString();
With an onclicklistener for the button that draws the data from the editText as well.
You just need to have this condition to check whether the value entered is between 1 to 800.
EditText editText2 = findViewById(R.id.editText2);
String tweetNo = editText2.getText().toString();
int result = Integer.parseInt(tweetNo); // convert String to int
if (result >= 1 && result <= 800){
// do whatever you want
}
You can use an InputFilter to limit the value.
editText2.setFilters(new InputFilter[]{new InputFilter() {
#Override
public CharSequence filter(CharSequence charSequence, int i, int i1, Spanned spanned, int i2, int i3) {
try{
int val=Integer.parseInt(spanned.toString()+charSequence.toString());
if(MIN<=val&&val<=MAX)
return null;
}catch (NumberFormatException e){
}
return "";
}
}});
You can set a custom InputFilter for your EditText. InputFilter defines what value is allowed inside the EditText, in your case we need to define a filter that accepts only values within the range of 0 to 800. Define the filter class like this:
public class CustomRangeInputFilter implements InputFilter {
private double minValue;
private double maxValue;
public CustomRangeInputFilter(double minVal, double maxVal) {
this.minValue = minVal;
this.maxValue = maxVal;
}
#Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dStart, int dEnd) {
try {
// Remove the string out of destination that is to be replaced
String newVal = dest.toString().substring(0, dStart) + dest.toString().substring(dEnd, dest.toString().length());
newVal = newVal.substring(0, dStart) + source.toString() + newVal.substring(dStart, newVal.length());
double input = Double.parseDouble(newVal);
if (isInRange(minValue, maxValue, input)) {
return null;
}
} catch (NumberFormatException e) {
e.printStackTrace();
}
return "";
}
private boolean isInRange(double a, double b, double c) {
return b > a ? c >= a && c <= b : c >= b && c <= a;
}
}
Then you set the filter on your EditText on the onCreate method:
editText.setFilters(new InputFilter[]{new CustomRangeInputFilter(0f, 800.0f)});
This question already has answers here:
Is there a way to define a min and max value for EditText in Android?
(29 answers)
Closed 3 years ago.
Is there a way to only allow numbers x through y to be entered in a EditText dynamically?
I.E don't even allow a number below x or above y to be entered?
For example x = 1 y = 12.
Of course i could solve this in Java after the user hit submit with the invalid numbers and prompt them to enter again. It's a time waster though.
Something like android:digits="01234..." but being able to specify n-th fields.
e.g
A range going from 1 to 12
The user should not get confused since they are entering a month number.
I am already using android:maxLength="2" but i need finer control.
It's a bit crude (given that I wrote it quickly) but could do something like this. I would remove the onClick method and create an OnFocusChangeListener and put the code in there.
Also from what it looks like you want something that checks Input as it's being entered and I don't really know if that's possible for a set range let alone that it'll probably cause the app to lag. As suggested by others, validation after Input is the logical route.
public void ValidateInputClick(View view) {
int Min = 1;
int Max = 12;
final TextInputLayout EditTextIP = (TextInputLayout) findViewById(R.id.layoutInput);
String str = EditTextIP.getEditText().getText().toString();
if (str.equals("") || str.contains("\n")) {
EditTextIP.setError("Cannot be blank");
EditTextIP.setErrorEnabled(true);
}
else {
int inputToInt = Integer.parseInt(str);
if (inputToInt >= Min && inputToInt <= Max) {
//Show number
Snackbar.make(view, str, Snackbar.LENGTH_SHORT).show();
EditTextIP.setErrorEnabled(false);
} else {
//Clear text
EditTextIP.getEditText().setText("");
//Show Error
EditTextIP.setError("Number must be between 1-12");
EditTextIP.setErrorEnabled(true);
}
}
}
XML:
<android.support.design.widget.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/layoutInput">
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/editText1"
android:hint="Please enter a number between 1 and 12"
android:maxLength="2"
android:onClick="ValidateInputClick"/>
</android.support.design.widget.TextInputLayout>
No need to do anything in xml.
Find EditText in code:
int minValue = 1;
int maxValue = 12;
EditText input = (EditText) findViewById(R.id.txtInput);
input.setInputType(InputType.TYPE_CLASS_NUMBER);
input.setFilters(new InputFilter[]
{
new InputFilterMinMax(minValue, maxValue),
new InputFilter.LengthFilter(String.valueOf(maxValue).length())
});
input.setKeyListener(DigitsKeyListener.getInstance("0123456789"));
Code for InputFilterMinMax:
public class InputFilterMinMax implements InputFilter {
private int min, max;
public InputFilterMinMax(int min, int max) {
this.min = min;
this.max = max;
}
#Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
try {
int input = Integer.parseInt(dest.toString() + source.toString());
if (isInRange(min, max, input))
return null;
} catch (NumberFormatException nfe) {
nfe.printStackTrace();
}
return "";
}
private boolean isInRange(int a, int b, int c) {
return b > a ? c >= a && c <= b : c >= b && c <= a;
}
}
Hope will help you!
I suggest that you still go for validation after Input. This is simply
logical, if you put yourself in End-User position. The user will try
to tap "99", yet you do not allow second digit to be more than 5. Are
you planning to somehow edit they soft-keyboard to only display
certain numbers in keyboard? That's waaay more confusing and time
consuming. Same would be with writting WARNING / INSTRUCTION messages
uppon user trying to write invalid number (= in this case you are anyway doing validation in background.
Check this SO answer for accessing certain digits in int:
SO: Accessing digits in int
And uppon entry just check for the 2nd digit, hence you allow for the first one to be from 1-9 (which is all).
if(secondDigit > 5){
// Warn the user of incorrect input
}
you can use Textwatcher for this.
please look at below code. In onTextChanged you can get which character is entered and count of Character entered.
TextWatcher textwatcher = getMandatoryTextWatcher(editText);
String text = editText.getText().toString();//At this point String text is not empty.
editText.addTextChangedListener(textwatcher);
public TextWatcher getMandatoryTextWatcher(final EditText editText) {
TextWatcher textwatcher = new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
//To change body of implemented methods use File | Settings | File Templates.
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
//To change body of implemented methods use File | Settings | File Templates.
}
#Override
public void afterTextChanged(Editable s) {
try {
//The first time this is called(the first softkey backspace press),
//text is empty. This causes a weird issue where the character that
//was just removed by pressing the backspace, reappears again.
//This is only the first time.
String text = editText.getText().toString();
if (text.length() <= 0) {
editText.setError(errorMandatory);
} else if (text.length() > 0) {
editText.setError(null);
} else {
editText.setError(errorMelding);
}
} catch (NumberFormatException nfe) {
editText.setError(errorMeldingTijdensParsen);
}
}
};
return textwatcher;
}
you can use something like this.
Hope this help you.
If your range is short and you don't need double numbers , I recommend you to use spinner for selecting numbers.
I'm working in an Android application and i want to create a decimal mask for editText in android. I want a mask like a maskMoney jQuery plugin. But in some cases my number will have 2 decimal places, 3 decimal places or will be a integer. I want do something like this:
When the EditText is created, come with a default value: 00.01
If user press the number 2, the result should be: 00.12
If user press the number 3, the result should be: 01.23
If user press the number 4, the result should be: 12.34
If user press the number 5, the result should be: 123.45
If user press the number 6, the result should be: 1,234.56
What's the best way to do that?
I resolved with this:
public static TextWatcher amount(final EditText editText, final String metric) {
return new TextWatcher() {
String current = "";
public void onTextChanged(CharSequence s, int start, int before, int count) {
if (!s.toString().equals(current)) {
editText.removeTextChangedListener(this);
String cleanString = s.toString();
if (count != 0) {
String substr = cleanString.substring(cleanString.length() - 2);
if (substr.contains(".") || substr.contains(",")) {
cleanString += "0";
}
}
cleanString = cleanString.replaceAll("[,.]", "");
double parsed = Double.parseDouble(cleanString);
DecimalFormat df = new DecimalFormat("0.00");
String formatted = df.format((parsed / 100));
current = formatted;
editText.setText(formatted);
editText.setSelection(formatted.length());
editText.addTextChangedListener(this);
}
}
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
public void afterTextChanged(Editable s) {}
};
}
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:
If the user enters a number with no decimals, the maximum number of digits must be 8
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)} );
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:
The user can enter a maximum of 8 digits;
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.
I have answser for you, me also suffered lot in this kind of situation.:D :P
I have implemented this for maximum of 4 digits to the left and 2 to the right of the decimal point ex: 4444.99
so small changes need to implement what i did:
Need to do following changes
1) copy CustomTextWatcher.java to track input of editText.
import java.text.NumberFormat;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.widget.EditText;
public class CustomTextWatcher implements TextWatcher {
private NumberFormat nf = NumberFormat.getNumberInstance();
private EditText et;
private String tmp = "";
private int moveCaretTo;
private static final int INTEGER_CONSTRAINT = 4;
private static final int FRACTION_CONSTRAINT = 2;
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 {
if (ss.contains(".")) {
String[] integerFractionStrings = ss.split("\\.");
Log.v("Check SS ", ss);
Log.v("second string", "Found"
+ integerFractionStrings.length);
if (integerFractionStrings.length > 1) {
Log.v("integerFractionStrings",
integerFractionStrings[1]);
if (integerFractionStrings[1].length() == 1
&& integerFractionStrings[1].charAt(0) == '0') {
et.setText(ss);
Log.v("second string", "size 1");
} else {
Log.v("second string", "> 1");
Double d = Double.parseDouble(ss);
if (d != null) {
et.setText(nf.format(d));
}
}
}
} else {
Log.v("First string", "No dot");
Double d = Double.parseDouble(ss);
if (d != null) {
et.setText(nf.format(d));
}
}
} catch (NumberFormatException e) {
}
}
} else {
Log.v("second string", "size 1");
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;
}
}
}
2) set this class to check your editText by following.
EditText review_food_Price;
review_food_Price = (EditText) findViewById(R.id.food_Price);
review_food_Price.setRawInputType(InputType.TYPE_CLASS_NUMBER
| InputType.TYPE_NUMBER_FLAG_DECIMAL);
review_food_Price.addTextChangedListener(new CustomTextWatcher(
review_food_Price));
Hope you can convert my code according to your need.
The problem that you describe is precisely what a Masked EditText is meant to be used for. :)