EditText with phone number that has a dash [duplicate] - java
Instead of 5118710, it should be 511-8710. I'd like to add a dash after the user the user inputted 3 digits already in the EditText. The maximum length of the EditText is 7 digits only.
After I figured out the above problem, I've got stuck in coding again. When I already inputted 3 digits, it appends dash (that's what I'd like to happen) but my problem here is that the next 3 digits also appends dash (Like this: 511-871-)... Please help me with this. thanks!
txt_HomeNo.addTextChangedListener(new TextWatcher() {
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
boolean flag = true;
String eachBlock[] = txt_HomeNo.getText().toString().split("-");
for (int i = 0; i < eachBlock.length; i++) {
if (eachBlock[i].length() > 3) {
flag = false;
}
}
if (flag) {
txt_HomeNo.setOnKeyListener(new OnKeyListener() {
#Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_DEL)
keyDel = 1;
return false;
}
});
if (keyDel == 0) {
if (((txt_HomeNo.getText().length() + 1) % 4) == 0) {
if (txt_HomeNo.getText().toString().split("-").length <= 3) {
txt_HomeNo.setText(txt_HomeNo.getText() + "-");
txt_HomeNo.setSelection(txt_HomeNo.getText().length());
}
}
a = txt_HomeNo.getText().toString();
} else {
a = txt_HomeNo.getText().toString();
keyDel = 0;
}
} else {
txt_HomeNo.setText(a);
}
}
The most straightforward solution is to use PhoneNumberFormattingTextWatcher which will format the number according to the system locale.
XML:
<EditText
android:id="#+id/phone_number"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="#string/enter_phone_number"
android:inputType="phone" />
Add addTextChangedListener() in your class:
EditText phoneNumber = (EditText)findViewById(R.id.phone_number);
phoneNumber.addTextChangedListener(new PhoneNumberFormattingTextWatcher());
Implement the following modified addTextChangedListener for txt_HomeNo. The code below is checking if the length of the text entered is 3 and if it is then add the - to it. Not a very robust solution but it works!
txt_HomeNo.addTextChangedListener(new TextWatcher() {
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
txt_HomeNo.setOnKeyListener(new OnKeyListener() {
#Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_DEL)
keyDel = 1;
return false;
}
});
if (keyDel == 0) {
int len = txt_HomeNo.getText().length();
if(len == 3) {
txt_HomeNo.setText(txt_HomeNo.getText() + "-");
txt_HomeNo.setSelection(txt_HomeNo.getText().length());
}
} else {
keyDel = 0;
}
}
#Override
public void afterTextChanged(Editable arg0) {
// TODO Auto-generated method stub
}
#Override
public void beforeTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {
// TODO Auto-generated method stub
}
});
I have a few small changes to the solution of neo108 so it can work with both soft keyboard and hard keyboard, in my code for example the edittext will follow the rule to automatically add " " at position 5 and 9.
txtPhone.addTextChangedListener(new TextWatcher() {
int keyDel;
#Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
#Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
txtPhone.setOnKeyListener(new View.OnKeyListener() {
#Override
public boolean onKey(View view, int keyCode, KeyEvent keyEvent) {
if (keyCode == KeyEvent.KEYCODE_DEL) {
keyDel = 1;
}
return false;
}
});
String currentString = txtPhone.getText().toString();
int currentLength = txtPhone.getText().length();
if (currentLength == 5 || currentLength == 9) {
keyDel = 1;
}
if (keyDel == 0) {
if (currentLength == 4 || currentLength == 8) {
txtPhone.setText(txtPhone.getText() + " ");
txtPhone.setSelection(txtPhone.getText().length());
}
} else {
if (currentLength != 5 && currentLength != 9) {
keyDel = 0;
} else if ((currentLength == 5 || currentLength == 9)
&& !" ".equals(currentString.substring(currentLength - 1, currentLength))) {
txtPhone.setText(currentString.substring(0, currentLength - 1) + " "
+ currentString.substring(currentLength - 1, currentLength));
txtPhone.setSelection(txtPhone.getText().length());
}
}
}
I implemented a custom TextWatcher; this handles 10 and 11 digit phone numbers (i.e. 1-555-867-5309 and 555-867-5309). Allows adds, deletions, inserts, mass removal while maintaining proper cursor position.
public class CustomPhoneTextWatcher implements TextWatcher {
private final EditText editText;
private String previousString;
public CustomPhoneTextWatcher(EditText editText) {
this.editText = editText;
}
#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) {
// if the previous editable ends with a dash and new is shorter than previous
// additionally remove preceding character
if (previousString != null && previousString.endsWith("-") && editable.toString().length() < previousString.length()) {
previousString = editable.toString();
String removedCharacterPriorToDash = editable.toString().substring(0, editable.length() - 1);
editText.setText(removedCharacterPriorToDash);
int position = editText.length();
Editable etext = editText.getText();
Selection.setSelection(etext, position);
} else {
previousString = editable.toString();
String numericString = StringUtils.removeNonnumeric(editable.toString());
int stringLength = numericString.length();
boolean startsWithOne = numericString.startsWith("1");
numericString = numericString.substring(0, Math.min(stringLength, 10 + (startsWithOne ? 1 : 0)));
int lastHyphenIndex = 6 + (startsWithOne ? 1 : 0);
int secondToLastHyphenIndex = 3 + (startsWithOne ? 1 : 0);
if (stringLength >= lastHyphenIndex) {
numericString = numericString.substring(0, lastHyphenIndex) + "-" + numericString.substring(lastHyphenIndex, numericString.length());
}
if (stringLength >= secondToLastHyphenIndex) {
numericString = numericString.substring(0, secondToLastHyphenIndex) + "-" + numericString.substring(secondToLastHyphenIndex, numericString.length());
}
if (numericString.startsWith("1")) {
numericString = numericString.substring(0, 1) + "-" + numericString.substring(1, numericString.length());
}
if (!numericString.equals(editable.toString())) {
editText.setText(numericString);
int position = editText.length();
Editable etext = editText.getText();
Selection.setSelection(etext, position);
}
}
}
}
StringUtils.removeNonnumeric(editable.toString()) is a call to this method:
public static String removeNonnumeric(String text) {
return text.replaceAll("[^\\d]", "");
}
Thanks for the all above answer.
The editText.setOnKeyListener() will never invoke when your device has only soft keyboard.
If we strictly follow the rule to add "-", then this code not always show desire result.
editText.addTextChangedListener(new PhoneNumberFormattingTextWatcher());
but above code is best solution for formatting phone no.
Apart from above this solution, I write a code which work on all types of condition::
phoneNumber.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) {
if (len > phoneNumber.getText().length() ){
len--;
return;
}
len = phoneNumber.getText().length();
if (len == 4 || len== 8) {
String number = phoneNumber.getText().toString();
String dash = number.charAt(number.length() - 1) == '-' ? "" : "-";
number = number.substring(0, (len - 1)) + dash + number.substring((len - 1), number.length());
phoneNumber.setText(number);
phoneNumber.setSelection(number.length());
}
}
});
this line of code required to add "-" on 3rd & 6th position of number.
if (len == 4 || len== 8)
Do it yourself by using OnEditTextChangedListener and insert dash by counting number of chars, Counting Chars in EditText Changed Listener
import android.text.Editable;
import android.text.Selection;
import android.text.TextWatcher;
import android.util.Log;
import android.widget.EditText;
/**
* Auto-formats a number using -.
* Ex. 303-333-3333
* Ex. 1-303-333-3333
* Doesn't allow deletion of just -
*/
public class PhoneNumberFormattingTextWatcher implements TextWatcher {
private static final String TAG = "PhoneNumberTextWatcher";
private final EditText editText;
private String previousNumber;
/**
* Indicates the change was caused by ourselves.
*/
private boolean mSelfChange = false;
public PhoneNumberFormattingTextWatcher(EditText editText) {
this.editText = editText;
}
#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) {
// if the previous editable ends with a dash and new is shorter than previous
// additionally remove preceding character
Log.i(TAG, "Previous String: " + previousNumber);
//if self change ignore
if (mSelfChange) {
Log.i(TAG, "Ignoring self change");
mSelfChange = false;
return;
}
String phoneNumber = removeNonnumeric(editable.toString());
int stringLength = phoneNumber.length();
//empty case
if(stringLength == 0) {
mSelfChange = true;
editText.setText("");
return;
}
boolean startsWithOne = phoneNumber.charAt(0) == '1';
int maxLength = 10 + (startsWithOne ? 1 : 0);
//too large
if(stringLength > maxLength) {
Log.i(TAG, "String length is greater than max allowed, using previous string: " + previousNumber);
mSelfChange = true;
editText.setText(previousNumber);
Editable etext = editText.getText();
Selection.setSelection(etext, previousNumber.length());
return;
}
phoneNumber = formatPhoneNumber(phoneNumber);
if(previousNumber != null && phoneNumber.length() == previousNumber.length()) {
//user deleting last character, and it is a -
if(phoneNumber.endsWith("-")) {
phoneNumber = phoneNumber.substring(0, phoneNumber.length()-2);
}
}
mSelfChange = true;
previousNumber = phoneNumber;
editText.setText(phoneNumber);
Editable etext = editText.getText();
Selection.setSelection(etext, phoneNumber.length());
}
private String formatPhoneNumber(String phoneNumber) {
int stringLength = phoneNumber.length();
//check if starts with 1, if it does, dash index is increased by 1
boolean startsWithOne = phoneNumber.charAt(0) == '1';
//if the length of the string is 6, add another dash
int lastHyphenIndex = 6 + (startsWithOne ? 1 : 0);
if (stringLength >= lastHyphenIndex) {
phoneNumber = phoneNumber.substring(0, lastHyphenIndex) + "-" + phoneNumber.substring(lastHyphenIndex, phoneNumber.length());
}
//if the length of the string is 3, add a dash
int secondToLastHyphenIndex = 3 + (startsWithOne ? 1 : 0);
if (stringLength >= secondToLastHyphenIndex) {
phoneNumber = phoneNumber.substring(0, secondToLastHyphenIndex) + "-" + phoneNumber.substring(secondToLastHyphenIndex, phoneNumber.length());
}
//If the number starts with 1, add a dash after 1
if (phoneNumber.startsWith("1")) {
phoneNumber = phoneNumber.substring(0, 1) + "-" + phoneNumber.substring(1, phoneNumber.length());
}
return phoneNumber;
}
private static String removeNonnumeric(String text) {
return text.replaceAll("[^\\d]", "");
}
}
Related
Prevent user to add text after 10 commas entered in edittext
I have to create a comma-separated array. So after 10 comma edittext should not accept the text or latter enter by user <- I have to do this. Here's the code I am using. but it goes to infinite loop after if condition in onTextChanged(). addTagsEt.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) { if (tagsArray != null && tagsArray.length == 10) { Toast.makeText(CreateJobTwoActivity.this, "Only 10 tags considered", Toast.LENGTH_SHORT).show(); addTagsEt.setText(addTagsEt.getText().toString().substring(0, addTagsEt.getText().toString().length() - 1)); } } #Override public void afterTextChanged(Editable s) { if (addTagsEt.getText().toString().contains(",")) { tagsArray = addTagsEt.getText().toString().split("\\s*,\\s*"); tagsArr.addAll(Arrays.asList(tagsArray)); } } });
Change onTextChanged function to: public void onTextChanged(CharSequence s, int start, int before, int count) { if (s.length() > 0) { String str = s.toString(); int l = str.length() - str.replaceAll(",","").length(); if (l >= 10){ Toast.makeText(CreateJobTwoActivity.this, "Only 10 tags considered", Toast.LENGTH_SHORT).show(); String t = str.substring(0,start) + str.substring(start+count); addTagsEt.setText(t); addTagsEt.setSelection(start,start); } } }
How to get the last word typed in a `EditText`?
I am building a proto social network and I give the possibility to my users to Tag another user with the # , I'm using an autocomplete textview to show the dialog with the users # searched but I need to know when a user typed "#" and the letters following in the editext . I found this answer and it's exaclty what I need BUT I dont want to only get one character. I want the whole word to make a search in my database . Example, user types "#Jordan" in the middle of his paste text . I need to get the "#" and the "#Jordan " . How can I do it ? Here s an example of my code private final TextWatcher textWatcher = 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) { if (!TextUtils.isEmpty(s) && start < s.length()) { if (!mentionAdapter.isEmpty()) { mentionAdapter.clear(); } String lastWord = s.toString().substring(s.toString().lastIndexOf(" ") + 1); if (lastWord != null){ if (lastWord.length() != 0) { switch (lastWord.charAt(0)) { case '#': if (getAdapter() != hashtagAdapter) { setAdapter(hashtagAdapter); } break; case '#': if (getAdapter() != mentionAdapter) { setAdapter(mentionAdapter); } break; } } } } } #Override public void afterTextChanged(Editable s) { } };
I am aiming you are working on android java so here is the answer to your question EditText editText = (EditText)findViewById(R.id.editText); editText.addTextChangedListener(new TextWatcher() { #Override public void afterTextChanged(Editable s) { // TODO Auto-generated method stub } #Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { // TODO Auto-generated method stub } #Override public void onTextChanged(CharSequence s, int start, int before, int count) { try { String capturedString = getText(s); } catch (Exception e) { e.printStackTrace(); } } }); this function will work whenever you tab spacebar "#Jordan " you will get string after '#' and before ' ' means you will get "Jordan" as a string public String getText(String s) { String startChar = "#"; String endChar = " "; String output = getStringBetweenTwoChars(s, startChar, endChar); System.out.println(output); } here is getStringBetweenTwoChars function public String getStringBetweenTwoChars(String input, String startChar, String endChar) { try { int start = input.indexOf(startChar); if (start != -1) { int end = input.indexOf(endChar, start + startChar.length()); if (end != -1) { return input.substring(start + startChar.length(), end); } } } catch (Exception e) { e.printStackTrace(); } return input; }
You can do that by following code, If you want to #java from the string **Hello this is #java the best programming language ** edt.addTextChangedListener(new TextWatcher() { #Override public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) { } #Override public void onTextChanged(final CharSequence s, int start, int before, int count) { } #Override public void afterTextChanged(Editable editable) { String str = editable.toString(); String seperator = "#"; int seoPos = str.indexOf(seperator); Pattern pattern = Pattern.compile("\\s"); Matcher matcher = pattern.matcher(str); boolean found = matcher.find(); if (seoPos != -1 && !found){ Log.d("TextChanged0","current Char "+str.substring(seoPos-1+seperator.length())); } } });
String last = s.toString().substring(s.toString().lastIndexOf(" ") + 1);
Changing TextInputLayout's Hint value as the user types in it
Here is my TextInputEditText inside TextInputLayout. The hint you can see is set on TextInputLayout. The user must write 255 characters otherwise the post is not valid. I want the digit 255 to decrease as the user types and when reached to 0, the hint should be blank. Here is my code : private int charactersLeft = 256; is declared outside onCreate method. And this code is inside onCreate method : final TextInputLayout postTextInputBase = findViewById(R.id.post_text_input_base); final TextInputEditText postTextInput = findViewById(R.id.post_text_input); postTextInput.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) { if (charactersLeft == 0) { postTextInputBase.setHint(null); } else { postTextInputBase.setHint((charactersLeft - 1) + " characters left"); } } #Override public void afterTextChanged(Editable s) { } }); I also tried to set charactersLeft to characterLeft -= 1 but, the java won't allow me to do that. Then, how do I do this ?
Use app:counterEnabled="true" Whether the character counter functionality is enabled or not in this layout. Also use app:counterMaxLength="250" Sets the max length to display at the character counter. Try this <android.support.design.widget.TextInputLayout android:id="#+id/post_text_input_base" android:layout_width="match_parent" android:layout_height="wrap_content" app:counterEnabled="true" app:counterMaxLength="250"> <EditText android:id="#+id/post_text_input" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="UserName" /> </android.support.design.widget.TextInputLayout> OUTPUT EDIT public class RecyclerViewActivity extends AppCompatActivity { TextInputLayout postTextInputBase; EditText postTextInputEditText; int textLength = 9; int len = 0; #Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_recycler_view); postTextInputBase = findViewById(R.id.post_text_input_base); postTextInputEditText = findViewById(R.id.post_text_input); postTextInputBase.setHint(textLength + " characters left"); postTextInputEditText.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) { // first check your EditText is empty or not if (!TextUtils.isEmpty(postTextInputEditText.getText().toString())) { int len = postTextInputEditText.getText().toString().length(); // than check that editText text length is less than max length or not // for test case i have set max length 10 if (len < 9) { // if length of text is less than max length than use minus one from max length and set error in your text input layout textLength--; } else { textLength++; } postTextInputBase.setHint(textLength + " characters left"); } else { textLength = 9; } } #Override public void afterTextChanged(Editable s) { if(postTextInputEditText.getText().toString().isEmpty()){ textLength = 9; postTextInputBase.setHint(textLength + " characters left"); } } }); } } OUTPUT EDIT 2 If you need set hint than use this postTextInputBase.setHint(textLength + " characters left"); OUTPUT NOTE Don't forgot to set android:maxLength="10" in edittext
Try this. Works with your existing code. int charactersLeft = 256; final TextInputLayout postTextInputBase = findViewById(R.id.post_text_input_base); final TextInputEditText postTextInput = findViewById(R.id.post_text_input); postTextInput.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) { if (s.length() == 0) { postTextInputBase.setHint(null); }else { postTextInputBase.setHint((charactersLeft - s.length()) + " characters left"); } } }); and Add android:maxLength="256" to your TextInputEditText
You may do it programatically using setOnKeyListener on the edit text. TextInputLayout postTextInputBase = findViewById(R.id.post_text_input_base); TextInputEditText postTextInput = findViewById(R.id.post_text_input); postTextInput.setOnKeyListener((v, keyCode, event) -> { // Do other things needed postTextInputBase.setHint("Characters left: " + (256 - postTextInput.getText().length())); return false; });
To change Hint text only you can just change it on focus change. editText.setOnFocusChangeListener(new View.OnFocusChangeListener() { #Override public void onFocusChange(View v, boolean hasFocus) { if(hasFocus) editText.setHint("Enter name"); else editText.setHint("Name"); } });
how to make User Input of 10 digit Mobile number into 3 - 3 - 4 pattern
How to make make user input of 10 digit mobile number into 3-3-4 format? example of 9848098480 into (984)-809-8480 in android??
Simply use the PhoneNumberFormattingTextWatcher, just call: editText.addTextChangedListener(new PhoneNumberFormattingTextWatcher()); Addition To be clear, PhoneNumberFormattingTextWatcher's backbone is the PhoneNumberUtils class. The difference is the TextWatcher maintains the EditText while you must call PhoneNumberUtils.formatNumber() every time you change its contents. OR You can use this: <EditText android:id="#+id/editText1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:inputType="phone" /> Then try this code: final EditText text = (EditText) findViewById(com.and.R.id.editText1); text.addTextChangedListener(new TextWatcher() { #Override public void onTextChanged(CharSequence s, int start, int before, int count) { boolean flag = true; String eachBlock[] = text.getText().toString().split("-"); for (int i = 0; i < eachBlock.length; i++) { if (eachBlock[i].length() > 4) { flag = false; } } if (flag) { text.setOnKeyListener(new OnKeyListener() { #Override public boolean onKey(View v, int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_DEL) keyDel = 1; return false; } }); if (keyDel == 0) { if (((text.getText().length() + 1) % 5) == 0) { if (text.getText().toString().split("-").length <= 3) { text.setText(text.getText() + "-"); text.setSelection(text.getText().length()); } } a = text.getText().toString(); } else { a = text.getText().toString(); keyDel = 0; } } else { text.setText(a); } } #Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { // TODO Auto-generated method stub } #Override public void afterTextChanged(Editable s) { } });
use Himanshu Agarwal's method or just do: String number = "1234567899"; System.out.println("(" + number.substring(0, 3) + ")-" + number.substring(3, 6) + "-" + number.substring(6)); ouput: (123)-456-7899
Limit Decimal Places in Android EditText
I'm trying to write an app that helps you manage your finances. I'm using an EditText Field where the user can specify an amount of money. I set the inputType to numberDecimal which works fine, except that this allows people to enter numbers such as 123.122 which is not perfect for money. Is there a way to limit the number of characters after the decimal point to two?
More elegant way would be using a regular expression ( regex ) as follows: 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) { Matcher matcher=mPattern.matcher(dest); if(!matcher.matches()) return ""; return null; } } To use it do: editText.setFilters(new InputFilter[] {new DecimalDigitsInputFilter(5,2)});
Simpler solution without using regex: import android.text.InputFilter; import android.text.Spanned; /** * Input filter that limits the number of decimal digits that are allowed to be * entered. */ public class DecimalDigitsInputFilter implements InputFilter { private final int decimalDigits; /** * Constructor. * * #param decimalDigits maximum decimal digits */ public DecimalDigitsInputFilter(int decimalDigits) { this.decimalDigits = decimalDigits; } #Override public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) { int dotPos = -1; int len = dest.length(); for (int i = 0; i < len; i++) { char c = dest.charAt(i); if (c == '.' || c == ',') { dotPos = i; break; } } if (dotPos >= 0) { // protects against many dots if (source.equals(".") || source.equals(",")) { return ""; } // if the text is entered before the dot if (dend <= dotPos) { return null; } if (len - dotPos > decimalDigits) { return ""; } } return null; } } To use: editText.setFilters(new InputFilter[] {new DecimalDigitsInputFilter(2)});
This implementation of InputFilter solves the problem. import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.method.DigitsKeyListener; public class MoneyValueFilter extends DigitsKeyListener { public MoneyValueFilter() { super(false, true); } private int digits = 2; public void setDigits(int d) { digits = d; } #Override public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) { CharSequence out = super.filter(source, start, end, dest, dstart, dend); // if changed, replace the source if (out != null) { source = out; start = 0; end = out.length(); } int len = end - start; // if deleting, source is empty // and deleting can't break anything if (len == 0) { return source; } int dlen = dest.length(); // Find the position of the decimal . for (int i = 0; i < dstart; i++) { if (dest.charAt(i) == '.') { // being here means, that a number has // been inserted after the dot // check if the amount of digits is right return (dlen-(i+1) + len > digits) ? "" : new SpannableStringBuilder(source, start, end); } } for (int i = start; i < end; ++i) { if (source.charAt(i) == '.') { // being here means, dot has been inserted // check if the amount of digits is right if ((dlen-dend) + (end-(i + 1)) > digits) return ""; else break; // return new SpannableStringBuilder(source, start, end); } } // if the dot is after the inserted part, // nothing can break return new SpannableStringBuilder(source, start, end); } }
Here is a sample InputFilter which only allows max 4 digits before the decimal point and max 1 digit after that. Values that edittext allows: 555.2, 555, .2 Values that edittext blocks: 55555.2, 055.2, 555.42 InputFilter filter = new InputFilter() { final int maxDigitsBeforeDecimalPoint=4; final int maxDigitsAfterDecimalPoint=1; #Override public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) { StringBuilder builder = new StringBuilder(dest); builder.replace(dstart, dend, source .subSequence(start, end).toString()); if (!builder.toString().matches( "(([1-9]{1})([0-9]{0,"+(maxDigitsBeforeDecimalPoint-1)+"})?)?(\\.[0-9]{0,"+maxDigitsAfterDecimalPoint+"})?" )) { if(source.length()==0) return dest.subSequence(dstart, dend); return ""; } return null; } }; mEdittext.setFilters(new InputFilter[] { filter });
I made some fixes for #Pinhassi solution. It handles some cases: 1.you can move cursor anywhere 2.minus sign handling 3.digitsbefore = 2 and digitsafter = 4 and you enter 12.4545. Then if you want to remove ".", it will not allow. 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 ""; } }
I don't like the other solution and I created my own. With this solution you can't enter more than MAX_BEFORE_POINT digit before the point and the decimals can't be more than MAX_DECIMAL. You just can't type the digit in excess, no other effects! In additional if you write "." it types "0." Set the EditText in the layout to: android:inputType="numberDecimal" Add the Listener in your onCreate. If you want modify the number of digits before and after the point edit the call to PerfectDecimal(str, NUMBER_BEFORE_POINT, NUMBER_DECIMALS), here is set to 3 and 2 EditText targetEditText = (EditText)findViewById(R.id.targetEditTextLayoutId); targetEditText.addTextChangedListener(new TextWatcher() { public void onTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {} public void beforeTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {} public void afterTextChanged(Editable arg0) { String str = targetEditText.getText().toString(); if (str.isEmpty()) return; String str2 = PerfectDecimal(str, 3, 2); if (!str2.equals(str)) { targetEditText.setText(str2); targetEditText.setSelection(str2.length()); } } }); Include this Funcion: public String PerfectDecimal(String str, int MAX_BEFORE_POINT, int MAX_DECIMAL){ if(str.charAt(0) == '.') str = "0"+str; int max = str.length(); String rFinal = ""; boolean after = false; int i = 0, up = 0, decimal = 0; char t; while(i < max){ t = str.charAt(i); if(t != '.' && after == false){ up++; if(up > MAX_BEFORE_POINT) return rFinal; }else if(t == '.'){ after = true; }else{ decimal++; if(decimal > MAX_DECIMAL) return rFinal; } rFinal = rFinal + t; i++; }return rFinal; } And it's done!
I achieved this with the help of TextWatcher by the following way final EditText et = (EditText) findViewById(R.id.EditText1); int count = -1; et.addTextChangedListener(new TextWatcher() { public void onTextChanged(CharSequence arg0, int arg1, int arg2,int arg3) { } public void beforeTextChanged(CharSequence arg0, int arg1,int arg2, int arg3) { } public void afterTextChanged(Editable arg0) { if (arg0.length() > 0) { String str = et.getText().toString(); et.setOnKeyListener(new OnKeyListener() { public boolean onKey(View v, int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_DEL) { count--; InputFilter[] fArray = new InputFilter[1]; fArray[0] = new InputFilter.LengthFilter(100); et.setFilters(fArray); //change the edittext's maximum length to 100. //If we didn't change this the edittext's maximum length will //be number of digits we previously entered. } return false; } }); char t = str.charAt(arg0.length() - 1); if (t == '.') { count = 0; } if (count >= 0) { if (count == 2) { InputFilter[] fArray = new InputFilter[1]; fArray[0] = new InputFilter.LengthFilter(arg0.length()); et.setFilters(fArray); //prevent the edittext from accessing digits //by setting maximum length as total number of digits we typed till now. } count++; } } } }); This solution will not allow the user to enter more than two digit after decimal point. Also you can enter any number of digits before decimal point. I hope this will help. Thank you.
The InputFilter I came up with allows you to configure the number of digits before and after the decimal place. Additionally, it disallows leading zeroes. public class DecimalDigitsInputFilter implements InputFilter { Pattern pattern; public DecimalDigitsInputFilter(int digitsBeforeDecimal, int digitsAfterDecimal) { pattern = Pattern.compile("(([1-9]{1}[0-9]{0," + (digitsBeforeDecimal - 1) + "})?||[0]{1})((\\.[0-9]{0," + digitsAfterDecimal + "})?)||(\\.)?"); } #Override public CharSequence filter(CharSequence source, int sourceStart, int sourceEnd, Spanned destination, int destinationStart, int destinationEnd) { // Remove the string out of destination that is to be replaced. String newString = destination.toString().substring(0, destinationStart) + destination.toString().substring(destinationEnd, destination.toString().length()); // Add the new string in. newString = newString.substring(0, destinationStart) + source.toString() + newString.substring(destinationStart, newString.length()); // Now check if the new string is valid. Matcher matcher = pattern.matcher(newString); if(matcher.matches()) { // Returning null indicates that the input is valid. return null; } // Returning the empty string indicates the input is invalid. return ""; } } // To use this InputFilter, attach it to your EditText like so: final EditText editText = (EditText) findViewById(R.id.editText); EditText.setFilters(new InputFilter[]{new DecimalDigitsInputFilter(4, 4)});
The requirement is 2 digits after decimal. There should be no limit for digits before decimal point. So, solution should be, public class DecimalDigitsInputFilter implements InputFilter { Pattern mPattern; public DecimalDigitsInputFilter() { mPattern = Pattern.compile("[0-9]*+((\\.[0-9]?)?)||(\\.)?"); } #Override public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) { Matcher matcher = mPattern.matcher(dest); if (!matcher.matches()) return ""; return null; } } And use it as, mEditText.setFilters(new InputFilter[]{new DecimalDigitsInputFilter()}); Thanks to #Pinhassi for the inspiration.
My solution is simple and works perfect! public class DecimalInputTextWatcher implements TextWatcher { private String mPreviousValue; private int mCursorPosition; private boolean mRestoringPreviousValueFlag; private int mDigitsAfterZero; private EditText mEditText; public DecimalInputTextWatcher(EditText editText, int digitsAfterZero) { mDigitsAfterZero = digitsAfterZero; mEditText = editText; mPreviousValue = ""; mRestoringPreviousValueFlag = false; } #Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { if (!mRestoringPreviousValueFlag) { mPreviousValue = s.toString(); mCursorPosition = mEditText.getSelectionStart(); } } #Override public void onTextChanged(CharSequence s, int start, int before, int count) { } #Override public void afterTextChanged(Editable s) { if (!mRestoringPreviousValueFlag) { if (!isValid(s.toString())) { mRestoringPreviousValueFlag = true; restorePreviousValue(); } } else { mRestoringPreviousValueFlag = false; } } private void restorePreviousValue() { mEditText.setText(mPreviousValue); mEditText.setSelection(mCursorPosition); } private boolean isValid(String s) { Pattern patternWithDot = Pattern.compile("[0-9]*((\\.[0-9]{0," + mDigitsAfterZero + "})?)||(\\.)?"); Pattern patternWithComma = Pattern.compile("[0-9]*((,[0-9]{0," + mDigitsAfterZero + "})?)||(,)?"); Matcher matcherDot = patternWithDot.matcher(s); Matcher matcherComa = patternWithComma.matcher(s); return matcherDot.matches() || matcherComa.matches(); } } Usage: myTextEdit.addTextChangedListener(new DecimalInputTextWatcher(myTextEdit, 2));
The simplest way to achieve that is: et.addTextChangedListener(new TextWatcher() { public void onTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) { String text = arg0.toString(); if (text.contains(".") && text.substring(text.indexOf(".") + 1).length() > 2) { et.setText(text.substring(0, text.length() - 1)); et.setSelection(et.getText().length()); } } public void beforeTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) { } public void afterTextChanged(Editable arg0) { } });
I have modified the above solutions and created following one. You can set number of digits before and after decimal point. public class DecimalDigitsInputFilter implements InputFilter { private final Pattern mPattern; public DecimalDigitsInputFilter(int digitsBeforeZero, int digitsAfterZero) { mPattern = Pattern.compile(String.format("[0-9]{0,%d}(\\.[0-9]{0,%d})?", digitsBeforeZero, digitsAfterZero)); } #Override public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) { Matcher matcher = mPattern.matcher(createResultString(source, start, end, dest, dstart, dend)); if (!matcher.matches()) return ""; return null; } private String createResultString(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) { String sourceString = source.toString(); String destString = dest.toString(); return destString.substring(0, dstart) + sourceString.substring(start, end) + destString.substring(dend); } }
Slightly improved #Pinhassi solution. Works very well. It validates concatenated strings. public class DecimalDigitsInputFilter implements InputFilter { Pattern mPattern; public DecimalDigitsInputFilter() { mPattern = Pattern.compile("([1-9]{1}[0-9]{0,2}([0-9]{3})*(\\.[0-9]{0,2})?|[1-9]{1}[0-9]{0,}(\\.[0-9]{0,2})?|0(\\.[0-9]{0,2})?|(\\.[0-9]{1,2})?)"); } #Override public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) { String formatedSource = source.subSequence(start, end).toString(); String destPrefix = dest.subSequence(0, dstart).toString(); String destSuffix = dest.subSequence(dend, dest.length()).toString(); String result = destPrefix + formatedSource + destSuffix; result = result.replace(",", "."); Matcher matcher = mPattern.matcher(result); if (matcher.matches()) { return null; } return ""; } }
Create a new class in Android kotlin with the name DecimalDigitsInputFilter class DecimalDigitsInputFilter(digitsBeforeDecimal: Int, digitsAfterDecimal: Int) : InputFilter { var mPattern: Pattern = Pattern.compile("[0-9]{0,$digitsBeforeDecimal}+((\\.[0-9]{0,$digitsAfterDecimal})?)||(\\.)?") override fun filter( source: CharSequence?, start: Int, end: Int, dest: Spanned?, dstart: Int, dend: Int ): CharSequence? { val matcher: Matcher = mPattern.matcher( dest?.subSequence(0, dstart).toString() + source?.subSequence( start, end ).toString() + dest?.subSequence(dend, dest.length).toString() ) if (!matcher.matches()) return "" else return null } } Call this class with the following line et_buy_amount.filters = (arrayOf<InputFilter>(DecimalDigitsInputFilter(8,2))) there are too many answers for the same but it will allow you to enter 8 digit before decimal and 2 digits after decimal other answers are accepting only 8 digits
Try using NumberFormat.getCurrencyInstance() to format your string before you put it into a TextView. Something like: NumberFormat currency = NumberFormat.getCurrencyInstance(); myTextView.setText(currency.format(dollars)); Edit - There is no inputType for currency that I could find in the docs. I imagine this is because there are some currencies that don't follow the same rule for decimal places, such as the Japanese Yen. As LeffelMania mentioned, you can correct user input by using the above code with a TextWatcher that is set on your EditText.
DecimalFormat form = new DecimalFormat("#.##", new DecimalFormatSymbols(Locale.US)); EditText et; et.setOnEditorActionListener(new TextView.OnEditorActionListener() { #Override public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { if (actionId == EditorInfo.IME_ACTION_DONE) { double a = Double.parseDouble(et.getText().toString()); et.setText(form.format(a)); } return false; } }); What this does is when you exit editing phase it formats the field to the right format. At them moment it has only 2 decimal charachters. I think this is pretty easy way to do this.
I really liked Pinhassi's answer, but noticed that after the user had entered the specified number digits after the decimal point you could no longer enter text to the left side of the decimal point. The problem was that the solution only tested the previous text that had been entered, not the current text being entered. So here is my solution that inserts the new character into the original text for validation. package com.test.test; import java.util.regex.Matcher; import java.util.regex.Pattern; import android.text.InputFilter; import android.text.Spanned; import android.util.Log; public class InputFilterCurrency implements InputFilter { Pattern moPattern; public InputFilterCurrency(int aiMinorUnits) { // http://www.regexplanet.com/advanced/java/index.html moPattern=Pattern.compile("[0-9]*+((\\.[0-9]{0,"+ aiMinorUnits + "})?)||(\\.)?"); } // InputFilterCurrency #Override public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) { String lsStart = ""; String lsInsert = ""; String lsEnd = ""; String lsText = ""; Log.d("debug", moPattern.toString()); Log.d("debug", "source: " + source + ", start: " + start + ", end:" + end + ", dest: " + dest + ", dstart: " + dstart + ", dend: " + dend ); lsText = dest.toString(); // If the length is greater then 0, then insert the new character // into the original text for validation if (lsText.length() > 0) { lsStart = lsText.substring(0, dstart); Log.d("debug", "lsStart : " + lsStart); // Check to see if they have deleted a character if (source != "") { lsInsert = source.toString(); Log.d("debug", "lsInsert: " + lsInsert); } // if lsEnd = lsText.substring(dend); Log.d("debug", "lsEnd : " + lsEnd); lsText = lsStart + lsInsert + lsEnd; Log.d("debug", "lsText : " + lsText); } // if Matcher loMatcher = moPattern.matcher(lsText); Log.d("debug", "loMatcher.matches(): " + loMatcher.matches() + ", lsText: " + lsText); if(!loMatcher.matches()) { return ""; } return null; } // CharSequence } // InputFilterCurrency And the call to set the editText filter editText.setFilters(new InputFilter[] {new InputFilterCurrency(2)}); Ouput with two decimal places 05-22 15:25:33.434: D/debug(30524): [0-9]*+((\.[0-9]{0,2})?)||(\.)? 05-22 15:25:33.434: D/debug(30524): source: 5, start: 0, end:1, dest: 123.4, dstart: 5, dend: 5 05-22 15:25:33.434: D/debug(30524): lsStart : 123.4 05-22 15:25:33.434: D/debug(30524): lsInsert: 5 05-22 15:25:33.434: D/debug(30524): lsEnd : 05-22 15:25:33.434: D/debug(30524): lsText : 123.45 05-22 15:25:33.434: D/debug(30524): loMatcher.matches(): true, lsText: 123.45 Ouput inserting a 5 in the middle 05-22 15:26:17.624: D/debug(30524): [0-9]*+((\.[0-9]{0,2})?)||(\.)? 05-22 15:26:17.624: D/debug(30524): source: 5, start: 0, end:1, dest: 123.45, dstart: 2, dend: 2 05-22 15:26:17.624: D/debug(30524): lsStart : 12 05-22 15:26:17.624: D/debug(30524): lsInsert: 5 05-22 15:26:17.624: D/debug(30524): lsEnd : 3.45 05-22 15:26:17.624: D/debug(30524): lsText : 1253.45 05-22 15:26:17.624: D/debug(30524): loMatcher.matches(): true, lsText: 1253.45
I improved on the solution that uses a regex by Pinhassi so it also handles the edge cases correctly. Before checking if the input is correct, first the final string is constructed as described by the android docs. public class DecimalDigitsInputFilter implements InputFilter { private Pattern mPattern; private static final Pattern mFormatPattern = Pattern.compile("\\d+\\.\\d+"); public DecimalDigitsInputFilter(int digitsBeforeDecimal, int digitsAfterDecimal) { mPattern = Pattern.compile( "^\\d{0," + digitsBeforeDecimal + "}([\\.,](\\d{0," + digitsAfterDecimal + "})?)?$"); } #Override public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) { String newString = dest.toString().substring(0, dstart) + source.toString().substring(start, end) + dest.toString().substring(dend, dest.toString().length()); Matcher matcher = mPattern.matcher(newString); if (!matcher.matches()) { return ""; } return null; } } Usage: editText.setFilters(new InputFilter[] {new DecimalDigitsInputFilter(5,2)});
I have changed answer №6 (by Favas Kv) because there You can put just point in the first position. final InputFilter [] filter = { new InputFilter() { #Override public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) { StringBuilder builder = new StringBuilder(dest); builder.replace(dstart, dend, source .subSequence(start, end).toString()); if (!builder.toString().matches( "(([1-9]{1})([0-9]{0,4})?(\\.)?)?([0-9]{0,2})?" )) { if(source.length()==0) return dest.subSequence(dstart, dend); return ""; } return null; } }};
All answers here are pretty complex I tried to make it much simpler.Look at my code and decide for yourself - int temp = 0; int check = 0; editText.addTextChangedListener(new TextWatcher() { #Override public void onTextChanged(CharSequence s, int start, int before, int count) { if(editText.getText().toString().length()<temp) { if(!editText.getText().toString().contains(".")) editText.setFilters(new InputFilter[] { new InputFilter.LengthFilter(editText.getText().toString().length()-1) }); else editText.setFilters(new InputFilter[] { new InputFilter.LengthFilter(editText.getText().toString().length()+1) }); } if(!editText.getText().toString().contains(".")) { editText.setFilters(new InputFilter[] { new InputFilter.LengthFilter(editText.getText().toString().length()+1) }); check=0; } else if(check==0) { check=1; editText.setFilters(new InputFilter[] { new InputFilter.LengthFilter(editText.getText().toString().length()+2) }); } } #Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { temp = editText.getText().toString().length(); } #Override public void afterTextChanged(Editable s) { // TODO Auto-generated method stub } });
Simple Helper class is here to prevent the user entering more than 2 digits after decimal : public class CostFormatter implements TextWatcher { private final EditText costEditText; public CostFormatter(EditText costEditText) { this.costEditText = costEditText; } #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 synchronized void afterTextChanged(final Editable text) { String cost = text.toString().trim(); if(!cost.endsWith(".") && cost.contains(".")){ String numberBeforeDecimal = cost.split("\\.")[0]; String numberAfterDecimal = cost.split("\\.")[1]; if(numberAfterDecimal.length() > 2){ numberAfterDecimal = numberAfterDecimal.substring(0, 2); } cost = numberBeforeDecimal + "." + numberAfterDecimal; } costEditText.removeTextChangedListener(this); costEditText.setText(cost); costEditText.setSelection(costEditText.getText().toString().trim().length()); costEditText.addTextChangedListener(this); } }
Simple BindingAdapter in Kotlin: #BindingAdapter("maxDecimalPlaces") fun TextInputEditText.limitDecimalPlaces(maxDecimalPlaces: Int) { filters += InputFilter { source, _, _, dest, dstart, dend -> val value = if (source.isEmpty()) { dest.removeRange(dstart, dend) } else { StringBuilder(dest).insert(dstart, source) } val matcher = Pattern.compile("([1-9][0-9]*)|([1-9][0-9]*\\.[0-9]{0,$maxDecimalPlaces})|(\\.[0-9]{0,$maxDecimalPlaces})").matcher(value) if (!matcher.matches()) "" else null } }
Like others said, I added this class in my project and set the filter to the EditText I want. The filter is copied from #Pixel's answer. I'm just putting it all together. public class DecimalDigitsInputFilter implements InputFilter { Pattern mPattern; public DecimalDigitsInputFilter() { mPattern = Pattern.compile("([1-9]{1}[0-9]{0,2}([0-9]{3})*(\\.[0-9]{0,2})?|[1-9]{1}[0-9]{0,}(\\.[0-9]{0,2})?|0(\\.[0-9]{0,2})?|(\\.[0-9]{1,2})?)"); } #Override public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) { String formatedSource = source.subSequence(start, end).toString(); String destPrefix = dest.subSequence(0, dstart).toString(); String destSuffix = dest.subSequence(dend, dest.length()).toString(); String result = destPrefix + formatedSource + destSuffix; result = result.replace(",", "."); Matcher matcher = mPattern.matcher(result); if (matcher.matches()) { return null; } return ""; } } Now set the filter in your EditText like this. mEditText.setFilters(new InputFilter[]{new DecimalDigitsInputFilter()}); Here one important thing is it does solves my problem of not allowing showing more than two digits after the decimal point in that EditText but the problem is when I getText() from that EditText, it returns the whole input I typed. For example, after applying the filter over the EditText, I tried to set input 1.5699856987. So in the screen it shows 1.56 which is perfect. Then I wanted to use this input for some other calculations so I wanted to get the text from that input field (EditText). When I called mEditText.getText().toString() it returns 1.5699856987 which was not acceptable in my case. So I had to parse the value again after getting it from the EditText. BigDecimal amount = new BigDecimal(Double.parseDouble(mEditText.getText().toString().trim())) .setScale(2, RoundingMode.HALF_UP); setScale does the trick here after getting the full text from the EditText.
Here is my solution: yourEditText.addTextChangedListener(new TextWatcher() { #Override public void onTextChanged(CharSequence s, int start, int before, int count) { NumberFormat formatter = new DecimalFormat("#.##"); double doubleVal = Double.parseDouble(s.toString()); yourEditText.setText(formatter.format(doubleVal)); } #Override public void beforeTextChanged(CharSequence s, int start, int count,int after) {} #Override public void afterTextChanged(Editable s) {} }); If the user enters a number with more than two numbers after the decimal point, it will be automatically corrected. I hope I have helped!
I've also came across this problem. I wanted to be able to reuse the code in many EditTexts. This is my solution: Usage : CurrencyFormat watcher = new CurrencyFormat(); priceEditText.addTextChangedListener(watcher); Class: public static class CurrencyFormat implements TextWatcher { public void onTextChanged(CharSequence arg0, int start, int arg2,int arg3) {} public void beforeTextChanged(CharSequence arg0, int start,int arg2, int arg3) {} public void afterTextChanged(Editable arg0) { int length = arg0.length(); if(length>0){ if(nrOfDecimal(arg0.toString())>2) arg0.delete(length-1, length); } } private int nrOfDecimal(String nr){ int len = nr.length(); int pos = len; for(int i=0 ; i<len; i++){ if(nr.charAt(i)=='.'){ pos=i+1; break; } } return len-pos; } }
#Meh for u.. txtlist.setFilters(new InputFilter[] { new DigitsKeyListener( Boolean.FALSE,Boolean.TRUE) { int beforeDecimal = 7; int afterDecimal = 2; #Override public CharSequence filter(CharSequence source, int start, int end,Spanned dest, int dstart, int dend) { String etText = txtlist.getText().toString(); String temp = txtlist.getText() + source.toString(); if (temp.equals(".")) { return "0."; } else if (temp.toString().indexOf(".") == -1) { // no decimal point placed yet if (temp.length() > beforeDecimal) { return ""; } } else { int dotPosition ; int cursorPositon = txtlistprice.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); } } });
A very late response: We can do it simply like this: etv.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) { if (s.toString().length() > 3 && s.toString().contains(".")) { if (s.toString().length() - s.toString().indexOf(".") > 3) { etv.setText(s.toString().substring(0, s.length() - 1)); etv.setSelection(edtSendMoney.getText().length()); } } } #Override public void afterTextChanged(Editable arg0) { } }
Here is the TextWatcher that allow only n number of digits after decimal point. TextWatcher private static boolean flag; public static TextWatcher getTextWatcherAllowAfterDeci(final int allowAfterDecimal){ TextWatcher watcher = new TextWatcher() { #Override public void onTextChanged(CharSequence s, int start, int before, int count) { // TODO Auto-generated method stub } #Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { // TODO Auto-generated method stub } #Override public void afterTextChanged(Editable s) { // TODO Auto-generated method stub String str = s.toString(); int index = str.indexOf ( "." ); if(index>=0){ if((index+1)<str.length()){ String numberD = str.substring(index+1); if (numberD.length()!=allowAfterDecimal) { flag=true; }else{ flag=false; } }else{ flag = false; } }else{ flag=false; } if(flag) s.delete(s.length() - 1, s.length()); } }; return watcher; } How to use yourEditText.addTextChangedListener(getTextWatcherAllowAfterDeci(1));
This works fine for me. It allows value to be entered even after focus changed and retrieved back. For example: 123.00, 12.12, 0.01, etc.. 1.Integer.parseInt(getString(R.string.valuelength)) Specifies the length of the input digits.Values accessed from string.xml file.It is quiet easy to change values. 2.Integer.parseInt(getString(R.string.valuedecimal)), this is for decimal places max limit. private InputFilter[] valDecimalPlaces; private ArrayList<EditText> edittextArray; valDecimalPlaces = new InputFilter[] { new DecimalDigitsInputFilterNew( Integer.parseInt(getString(R.string.valuelength)), Integer.parseInt(getString(R.string.valuedecimal))) }; Array of EditText values that allows to perform action. for (EditText etDecimalPlace : edittextArray) { etDecimalPlace.setFilters(valDecimalPlaces); I just used array of values that contain multiple edittext Next DecimalDigitsInputFilterNew.class file. import android.text.InputFilter; import android.text.Spanned; public class DecimalDigitsInputFilterNew implements InputFilter { private final int decimalDigits; private final int before; public DecimalDigitsInputFilterNew(int before ,int decimalDigits) { this.decimalDigits = decimalDigits; this.before = before; } #Override public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) { StringBuilder builder = new StringBuilder(dest); builder.replace(dstart, dend, source .subSequence(start, end).toString()); if (!builder.toString().matches("(([0-9]{1})([0-9]{0,"+(before-1)+"})?)?(\\.[0-9]{0,"+decimalDigits+"})?")) { if(source.length()==0) return dest.subSequence(dstart, dend); return ""; } return null; } }
This is to build on pinhassi's answer - the issue that I came across was that you couldn't add values before the decimal once the decimal limit has been reached. To fix the issue, we need to construct the final string before doing the pattern match. import java.util.regex.Matcher; import java.util.regex.Pattern; import android.text.InputFilter; import android.text.Spanned; public class DecimalLimiter implements InputFilter { Pattern mPattern; public DecimalLimiter(int digitsBeforeZero,int digitsAfterZero) { mPattern=Pattern.compile("[0-9]{0," + (digitsBeforeZero) + "}+((\\.[0-9]{0," + (digitsAfterZero) + "})?)||(\\.)?"); } #Override public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) { StringBuilder sb = new StringBuilder(dest); sb.insert(dstart, source, start, end); Matcher matcher = mPattern.matcher(sb.toString()); if(!matcher.matches()) return ""; return null; } }