Force Trailing Zeroes in EditText Android - android

I copied code from stackoverflow using InputFilter to force the edit text to have 3 digits before the "." and 2 digits after (2 decimal places). However, I want the system to display 15.00 if user only enters 15?
So scenario I want is.. edit text must have 2 decimal places maximum.. e.g. 12.56 but if user only enters 15 then edit text field adds 2 zeros in the end so 15 -> 15.00
How do i do this in the addTextChangedListener?
Code from stackoverflow regarding inputfilter
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) {
String s = Html.toHtml(dest).replaceAll("\\<.*?>","").replaceAll("\n","");
Matcher matcher = mPattern.matcher(dest);
if (!matcher.matches())
return "";
try {
if(Double.parseDouble(s)<9999.99 && s.contains(".")) {
return null;
}else if ((Double.parseDouble(s)<1000 && !s.contains("."))||source.equals(".")) {
return null;
}else {
return "";
}
}catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
/// in main activity
numberReceivedEditText.setFilters(new InputFilter[]{new DecimalDigitsInputFilter(3, 2)});
numberReceivedEditText.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
#Override
public void afterTextChanged(Editable s) {
}
});

Please try this
numberReceivedEditText.setFilters(new InputFilter[]{new DecimalDigitsInputFilter(numberReceivedEditText)});
numberReceivedEditText.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
#Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
if (i2 == 0) return;
int cursorLocation = numberReceivedEditText.getSelectionStart();
String data = numberReceivedEditText.getText().toString();
if (!data.isEmpty()) {
if (!data.contains(".")) {
data = data + ".";
}
try {
data = String.format(Locale.JAPANESE, "%.2f", Double.parseDouble(data));
numberReceivedEditText.removeTextChangedListener(this);
numberReceivedEditText.setText(data);
numberReceivedEditText.setSelection(cursorLocation < data.length() ? cursorLocation : cursorLocation - 1, cursorLocation);
numberReceivedEditText.addTextChangedListener(this);
}catch (Exception e){
e.printStackTrace();
}
}
}
#Override
public void afterTextChanged(Editable editable) {
}
});
class DecimalDigitsInputFilter implements InputFilter {
TextView tvNumber;
public DecimalDigitsInputFilter(TextView tvNumber) {
this.tvNumber = tvNumber;
}
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
try {
if (Double.parseDouble(tvNumber.getText().toString()) > 1000) {
String[] splitValue = tvNumber.getText().toString().split("\\.");
return splitValue[0].substring(0,3) + "." + splitValue[1];
}
} catch (Exception e) {
return source;
}
return null;
}
}

Related

Override getText's EditText

I want to override getText() of EditText.
I receive this kind of String: "12,345,678"
My purpose is to just remove the commas and return the Editable but when with my code I get an error.
public class AmountEditText extends EditText {
#Override
public Editable getText() {
Editable s = super.getText();
if(s!=null && s.length()>0) {
if (s.toString().contains(",")) {
return new SpannableStringBuilder(s.toString().replace(",", ""));
}
}
return s;
}
private TextWatcher watcher = new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
int position = getSelectionStart();
int nbCommaBefore;
int nbCommaAfter;
String str = s.toString();
String finalStr;
String formattedStr;
nbCommaBefore = str.length() - str.replace(",", "").length();
boolean containsDot = false;
if (str.contains(".")) {
containsDot = true;
formattedStr = str.split("\\.")[0];
} else {
formattedStr = str;
}
if (!s.toString().isEmpty()) {
removeTextChangedListener(watcher);
formattedStr = formattedStr.replace(",", "");
formattedStr = formattedStr.replaceAll("(\\d)(?=(\\d{3})+$)", "$1,");
if (containsDot) {
if (str.split("\\.").length != 1) {
finalStr = formattedStr + "." + str.split("\\.")[1].replace(",", "");
} else {
finalStr = formattedStr + ".";
}
} else {
finalStr = formattedStr;
}
nbCommaAfter = finalStr.length() - finalStr.replace(",", "").length();
setText(finalStr);
if (position == str.length()){
setSelection(finalStr.length());
}
else if (position == 0)
{
setSelection(0);
}
else if (nbCommaBefore < nbCommaAfter){
setSelection(position + 1);
}
else if (nbCommaAfter < nbCommaBefore){
setSelection(position - 1);
}
else{
setSelection(position);
}
addTextChangedListener(watcher);
}
}
#Override
public void afterTextChanged(Editable s) {
}
};
public AmountEditText(Context context) {
this(context, null);
}
public AmountEditText(Context context, AttributeSet attrs) {
super(context, attrs);
addTextChangedListener(watcher);
}
public AmountEditText(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
addTextChangedListener(watcher);
}
}
E/MessageQueue-JNI: Exception in MessageQueue callback:
handleReceiveCallback E/MessageQueue-JNI:
java.lang.IndexOutOfBoundsException: setSpan (0 ... 5) ends beyond
length 4
at android.text.SpannableStringBuilder.checkRange(SpannableStringBuilder.java:1265)
at android.text.SpannableStringBuilder.setSpan(SpannableStringBuilder.java:684)
at android.text.SpannableStringBuilder.setSpan(SpannableStringBuilder.java:677)
at android.widget.SpellChecker$SpellParser.setRangeSpan(SpellChecker.java:532)
at android.widget.SpellChecker$SpellParser.parse(SpellChecker.java:515)
at android.widget.SpellChecker.spellCheck(SpellChecker.java:242)
at android.widget.Editor.updateSpellCheckSpans(Editor.java:679)
at android.widget.Editor.sendOnTextChanged(Editor.java:1249)
at android.widget.TextView.sendOnTextChanged(TextView.java:8191)
at android.widget.TextView.setText(TextView.java:4483)
at android.widget.TextView.setText(TextView.java:4337)
at android.widget.EditText.setText(EditText.java:89)
at android.widget.TextView.setText(TextView.java:4312)
at org.newtonproject.newpay.widgetlib.AmountEditText$1.onTextChanged(AmountEditText.java:74)
I would like to precise that the error doesn't come from my onTextChanged
because everything works well without the getText() override
EDIT : The user can enter number, I will append some commas in order to format the number. But when I override getText() I want to delete these commas in that way I don't have to filter the return of getText() everytime
Ok, I debugged that and found out that the problem was on that line
if (position == str.length()){
setSelection(finalStr.length());
}
lenght() is out of bound for a set selection, since it's 0 based
just change your code with that and it will work properly
if (position == str.length()){
setSelection(finalStr.length() - 1);
}
If needed, full code here (I used AppCompatEditText, but it's the same):
public class AmountEditText extends android.support.v7.widget.AppCompatEditText {
#Override
public Editable getText() {
Editable s = super.getText();
if(s!=null && s.length()>0) {
if (s.toString().contains(",")) {
return new SpannableStringBuilder(s.toString().replace(",", ""));
}
}
return s;
}
private TextWatcher watcher = new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
int position = getSelectionStart();
int nbCommaBefore;
int nbCommaAfter;
String str = s.toString();
String finalStr;
String formattedStr;
nbCommaBefore = str.length() - str.replace(",", "").length();
boolean containsDot = false;
if (str.contains(".")) {
containsDot = true;
formattedStr = str.split("\\.")[0];
} else {
formattedStr = str;
}
if (!s.toString().isEmpty()) {
removeTextChangedListener(watcher);
formattedStr = formattedStr.replace(",", "");
formattedStr = formattedStr.replaceAll("(\\d)(?=(\\d{3})+$)", "$1,");
if (containsDot) {
if (str.split("\\.").length != 1) {
finalStr = formattedStr + "." + str.split("\\.")[1].replace(",", "");
} else {
finalStr = formattedStr + ".";
}
} else {
finalStr = formattedStr;
}
nbCommaAfter = finalStr.length() - finalStr.replace(",", "").length();
setText(finalStr);
if (position == str.length()){
setSelection(finalStr.length() - 1);
}
else if (position == 0)
{
setSelection(0);
}
else if (nbCommaBefore < nbCommaAfter){
setSelection(position + 1);
}
else if (nbCommaAfter < nbCommaBefore){
setSelection(position - 1);
}
else{
setSelection(position);
}
addTextChangedListener(watcher);
}
}
#Override
public void afterTextChanged(Editable s) {
}
};
public AmountEditText(Context context) {
this(context, null);
}
public AmountEditText(Context context, AttributeSet attrs) {
super(context, attrs);
addTextChangedListener(watcher);
}
public AmountEditText(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
addTextChangedListener(watcher);
}
}
Let me know if that helped!
In your case, you can not override getText() and resize and using TextWatcher at same time.
Check the android source code below and you will why
SpannableStringBuilder.java
public void setSpan(Object what, int start, int end, int flags) {
setSpan(true, what, start, end, flags, true/*enforceParagraph*/);
}
private void setSpan(boolean send, Object what, int start, int end, int flags,
boolean enforceParagraph) {
checkRange("setSpan", start, end);
}
private void checkRange(final String operation, int start, int end) {
...
int len = length();
if (start > len || end > len) {
throw new IndexOutOfBoundsException(operation + " " +
region(start, end) + " ends beyond length " + len); // here is you exception
}
}
public int length() {
return mText.length - mGapLength;
}
SpellChecker.java
private void setRangeSpan(Editable editable, int start, int end) {
...
editable.setSpan(mRange, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
public void parse(int start, int end) {
...
if (parseEnd > start) {
setRangeSpan((Editable) mTextView.getText(), start, parseEnd); // I think the error happened from here, they use your getText() function here and receive shorter string, but the start, parseEnd still stick with original string
parse();
}
}
Solution .
You can simple defind a new function like getBeautifulText().
Try this one it will help's you
editText.addTextChangedListener(new TextWatcher() {
boolean isEdiging;
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
public void afterTextChanged(Editable s) {
if (isEdiging) return;
isEdiging = true;
String str = s.toString().replaceAll("[^\\d]", "");
double s1 = 0;
try {
s1 = Double.parseDouble(str);
} catch (NumberFormatException e) {
e.printStackTrace();
}
NumberFormat nf2 = NumberFormat.getInstance(Locale.ENGLISH);
((DecimalFormat) nf2).applyPattern("###,###.###");
s.replace(0, s.length(), nf2.format(s1));
if (s.toString().equals("0")) {
editText.setText("");
}
isEdiging = false;
}
});
Based on the requirements in your question:
The user can enter number, I will append some commas in order to
format the number. But when I override getText() I want to delete
these commas
I believe you could use a much simpler solution involving DecimalFormat:
class Formatter {
private final DecimalFormat f = new DecimalFormat(",###");
private final DecimalFormat o = new DecimalFormat("#");
String withCommas(String in) {
try {
return withCommas(Long.parseLong(in));
} catch (NumberFormatException e) {
e.printStackTrace();
return withCommas(Long.MIN_VALUE);
}
}
String withCommas(long in) {
return f.format(in);
}
Number stripCommas(String in) {
try {
return f.parse(in);
} catch (ParseException e) {
return Long.MIN_VALUE;
}
}
String stripCommasAsString(String in) {
return o.format(stripCommas(in));
}
}
Which gives:
final long num = 12345678L;
final Formatter f = new Formatter();
assertEquals("12,345,678", f.withCommas("12345678"));
assertEquals("12,345,678", f.withCommas(num));
assertEquals(num, f.stripCommas("12,345,678");
assertEquals("12345678", f.stripCommasAsString("12,345,678"));

Specific number of characters as letters and the succeeding characters as numbers

I want the user to type only letters in the first 5 characters and the next characters would only be numbers.
I've read the answer from this link: Validation allow only number and characters in edit text in android
However when I tried to do what I wanted to do, I'm getting error saying this:
java.lang.StringIndexOutOfBoundsException: length=1; index=1
at java.lang.String.charAt(Native Method)
The codes I've tried to do what I want.
InputFilter filter = new InputFilter() {
public CharSequence filter(CharSequence source, int start,
int end, Spanned dest, int dstart, int dend) {
for (int i = start;i < etLettersAndNumbers.getText().length();i++) {
if (etLettersAndNumbers.getText().length() < 4) {
if (!Character.isLetter(source.charAt(i))) {
return "";
}
}
if (etLettersAndNumbers.getText().length() >= 4) {
if (!Character.isDigit(source.charAt(i))) {
return "";
}
}
}
return null;
}
};
etLettersAndNumbers.setFilters(new InputFilter[] {filter});
I'm using dynamic EditText.
try this:
public void set(final EditText etLettersAndNumbers) {
etLettersAndNumbers.addTextChangedListener(new TextWatcher() {
int len = 0;
#Override
public void afterTextChanged(Editable s) {
}
#Override
public void beforeTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
String str = etLettersAndNumbers.getText().toString();
char[] st = str.toCharArray();
try {
if (Character.isLetter(st[st.length - 1]) && st.length - 1 < 5) {
System.out.print("Nothing");
} else if (!Character.isLetter(st[st.length - 1]) && st.length - 1 < 5) {
if(count>0)
etLettersAndNumbers.setText("");
} else if (Character.isLetter(st[st.length - 1]) && st.length - 1 >= 5) {
if(count>0)
etLettersAndNumbers.setText("");
}
} catch (Exception e) {
e.getMessage();
}
}
});
}

How can I create a EditTextPreference which accept only a predefined range value?

I hope that the EditTextPreference accept only a value between 6000 and 65536, how can I do? Thanks!
BTW, the code A doesn't work, I can't input any number in the edit box of EditTextPreference which key is "WebServerPort"
<EditTextPreference
android:key="WebServerPort"
android:defaultValue="6000"
android:title="Port"
android:summary="Set port for web server, it should be greater than 6000 and less than 65536"
android:inputType="number"
android:layout="#layout/layout_customize_preference_item"
/>
Code A
public class UIPreference extends PreferenceActivity {
private AdView adView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.mypreference);
setContentView(R.layout.layout_preference);
EditTextPreference edit_Pref = (EditTextPreference) getPreferenceScreen().findPreference("WebServerPort");
edit_Pref.getEditText().setFilters(new InputFilter[]{ new InputFilterMinMax("6000", "65536")});
}
}
class InputFilterMinMax implements InputFilter {
private int min, max;
public InputFilterMinMax(int min, int max) {
this.min = min;
this.max = max;
}
public InputFilterMinMax(String min, String max) {
this.min = Integer.parseInt(min);
this.max = Integer.parseInt(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) { }
return "";
}
private boolean isInRange(int a, int b, int c) {
return b > a ? c >= a && c <= b : c >= b && c <= a;
}
}
You can assign a TextWatcher to your EditText and listen for text changes there, for example:
editTextPreference.getEditText().addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
#Override
public void afterTextChanged(Editable s) {
try {
long val = Long.parseLong(s.toString());
if(val > 65536) {
s.replace(0, s.length(), "65536", 0, 5);
} else if(val < 6000) {
s.replace(0, s.length(), "6000", 0, 4);
}
} catch (NumberFormatException ex) {
// Do something
}
}
});
Try adding InputFilter on editTextPreference.getEditText()
InputFilter filter = new InputFilter() {
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
int number = 0;
try {
number = Integer.parseInt(source.toString());
} catch (Exception e) {
}
if(number > 6000 && number < 65536) {
return source;
}
return null;
}
};
editTextPreference.getEditText().setFilters(new InputFilter[] { filter });

Android EditText InputFilter

How to delete two character at once with the filter?
I am trying to apply a simple filter to an EditText.
It must work as follows:
(want to receive format: 1234 5678....)
===> EDITED: First part works well.
1) when there are 4 digits in EditText and I am entering the 5-th digit -
first must appear a space and then this digit.
2) And I need a reverse for this (during characters deletion) -
the space must be deleted with the 5-th digit.
What is wrong with my code?
editText.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) {
// any chars except backspace
if (!source.equals("")) {
if (dest.length() == 4) {
// here I must add a space and then the source
// ===> EDITED:
return " " + source;
// return super.filter(" " + source, start, end + 1, dest, dstart, dend + 1);
} // backspace entered
} else {
if (dest.length() == 6) {
// here I must delete the 6-th character
// and the space before
return super.filter(source, 0, 0, dest, 5, 6);
}
}
return null;
}
}});
Please use this
public class CustomFormatWatcher implements TextWatcher {
private int size;
public CustomFormatWatcher(int size) {
this.size = size;
}
#Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
#Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
#Override
public void afterTextChanged(Editable editable) {
char hyphen = ' ';
char c = 0;
if (editable.length() > 0) {
c = editable.charAt(editable.length() - 1);
if (c == hyphen) {
editable.delete(editable.length() - 1, editable.length());
}
}
if (editable.length() > 0 && (editable.length() % size) == 0) {
c = editable.charAt(editable.length() - 1);
if (hyphen == c) {
editable.delete(editable.length() - 1, editable.length());
}
}
if (editable.length() > 0 && (editable.length() % size) == 0) {
c = editable.charAt(editable.length() - 1);
// Only if its a digit where there should be a space we insert a hyphen
if (Character.isDigit(c) && TextUtils.split(editable.toString(), String.valueOf(hyphen)).length <= 3) {
editable.insert(editable.length() - 1, String.valueOf(hyphen));
}
}
}
}
and then use
myEditText.addTextChangedListener(new CustomFormatWatcher());
I suggest you to use TextWatcher to format your EditText input, because InputFilter is generally used for input restrictions, to decides what can be typed not to format the text.
You'll get your desired output with this code:
String mTextValue;
Character mLastChar = '\0'; // init with empty character
int mKeyDel;
myEditText.addTextChangedListener(new TextWatcher() {
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
String eachBlock[] = myEditText.getText().toString().split(" ");
myEditText.setOnKeyListener(new View.OnKeyListener() {
#Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_DEL)
mKeyDel = 1;
return false;
}
});
if (mKeyDel == 0) {
if (((myEditText.getText().length() + 1) % 5) == 0) {
myEditText.setText(myEditText.getText() + " ");
myEditText.setSelection(myEditText.getText().length());
}
mTextValue = myEditText.getText().toString();
} else {
mTextValue = myEditText.getText().toString();
if (mLastChar.equals(' ')) {
mTextValue = mTextValue.substring(0, mTextValue.length() - 1);
myEditText.setText(mTextValue);
myEditText.setSelection(mTextValue.length());
}
mKeyDel = 0;
}
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
if (s.length()>0) {// save the last char value
mLastChar = s.charAt(s.length() - 1);
} else {
mLastChar = '\0';
}
}
#Override
public void afterTextChanged(Editable s) {}
});

National letter selector doesn't appear

What I had to do was to implement a text input able to color letters green or red. My piece of code can do this but there is a problem. I can't write an national letter because the popup does not appear.
edit_text.addTextChangedListener(new TextWatcher() {
boolean input_changed = false;
private boolean isInputBlocked()
{
this.input_changed = !this.input_changed;
return !this.input_changed;
}
#Override
public void afterTextChanged(Editable s)
{
// Prevent recursive
if (isInputBlocked()) return;
// Some staff
Outer.this.edit_text.setText(Html.fromHtml(html_input.toString()));
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {}
#Override
public void onTextChanged(CharSequence s, int start, int before,
int count)
{}
});
When I commented Outer.this.edit_text.setText(Html.fromHtml(html_input.toString()));, the popup appears.
The InputFilter helped me resolve the problem:
InputFilter filter = new InputFilter() {
final String good_letter = "<font color='#2FEE0D'>$</font>";
final String bad_letter = "<font color='#FF0000'>$</font>";
public CharSequence filter(CharSequence source, int start, int end,
Spanned dest, int dstart, int dend)
{
String input = dest.toString().substring(0, dstart) + source.
subSequence(start, end) + dest.toString().substring(dend);
StringBuffer output = new StringBuffer();
List<Entry<Character, Boolean>> correction = Learn.this.
learn_manager.getLetters(input);
Log.d(TAG, "afterTextChanged: input size (" + input.length() +
")");
System.out.println(input);
for (int i = dstart; i < dstart + end; i++)
{
if (correction.get(i).getValue())
{
output.append(this.good_letter.replace('$', correction.
get(i).getKey()));
} else {
output.append(this.bad_letter.replace('$', correction.
get(i).getKey()));
}
}
return Html.fromHtml(output.toString());
}
};

Categories

Resources