Format credit card in edit text in android
After finding multiple answers that are 'OK'. I moved towards a better TextWatcher which is designed to work correctly and independently from the TextView
.
TextWatcher class is as follows:
/** * Formats the watched EditText to a credit card number */public static class FourDigitCardFormatWatcher implements TextWatcher { // Change this to what you want... ' ', '-' etc.. private static final char space = ' '; @Override public void onTextChanged(CharSequence s, int start, int before, int count) { } @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { } @Override public void afterTextChanged(Editable s) { // Remove spacing char if (s.length() > 0 && (s.length() % 5) == 0) { final char c = s.charAt(s.length() - 1); if (space == c) { s.delete(s.length() - 1, s.length()); } } // Insert char where needed. if (s.length() > 0 && (s.length() % 5) == 0) { char c = s.charAt(s.length() - 1); // Only if its a digit where there should be a space we insert a space if (Character.isDigit(c) && TextUtils.split(s.toString(), String.valueOf(space)).length <= 3) { s.insert(s.length() - 1, String.valueOf(space)); } } }}
Then add it to your TextView as you would any other TextWatcher
.
{ //... mEditTextCreditCard.addTextChangedListener(new FourDigitCardFormatWatcher()); }
This will auto delete the space sensibly going back so the user can actually do less keystrokes when editing.
Caveat
If you are using inputType="numberDigit"
this will disable the '-' and ' ' chars, so I recommend using, inputType="phone"
. This enables other chars, but just use a custom inputfilter and problem solved.
Late answer, but I guess it may helpful for somebody:
cardNumberEditText.addTextChangedListener(new TextWatcher() { private static final int TOTAL_SYMBOLS = 19; // size of pattern 0000-0000-0000-0000 private static final int TOTAL_DIGITS = 16; // max numbers of digits in pattern: 0000 x 4 private static final int DIVIDER_MODULO = 5; // means divider position is every 5th symbol beginning with 1 private static final int DIVIDER_POSITION = DIVIDER_MODULO - 1; // means divider position is every 4th symbol beginning with 0 private static final char DIVIDER = '-'; @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { // noop } @Override public void onTextChanged(CharSequence s, int start, int before, int count) { // noop } @Override public void afterTextChanged(Editable s) { if (!isInputCorrect(s, TOTAL_SYMBOLS, DIVIDER_MODULO, DIVIDER)) { s.replace(0, s.length(), buildCorrectString(getDigitArray(s, TOTAL_DIGITS), DIVIDER_POSITION, DIVIDER)); } } private boolean isInputCorrect(Editable s, int totalSymbols, int dividerModulo, char divider) { boolean isCorrect = s.length() <= totalSymbols; // check size of entered string for (int i = 0; i < s.length(); i++) { // check that every element is right if (i > 0 && (i + 1) % dividerModulo == 0) { isCorrect &= divider == s.charAt(i); } else { isCorrect &= Character.isDigit(s.charAt(i)); } } return isCorrect; } private String buildCorrectString(char[] digits, int dividerPosition, char divider) { final StringBuilder formatted = new StringBuilder(); for (int i = 0; i < digits.length; i++) { if (digits[i] != 0) { formatted.append(digits[i]); if ((i > 0) && (i < (digits.length - 1)) && (((i + 1) % dividerPosition) == 0)) { formatted.append(divider); } } } return formatted.toString(); } private char[] getDigitArray(final Editable s, final int size) { char[] digits = new char[size]; int index = 0; for (int i = 0; i < s.length() && index < size; i++) { char current = s.charAt(i); if (Character.isDigit(current)) { digits[index] = current; index++; } } return digits; } });
this works perfectly with start-string/end-string/mid-string editing, also paste works perfectly.
I modified Chris Jenkins answer to make it more robust. With this, even if the user edits the middle of the text, the spacing characters are still inserted (and automatically removed on wrong places) correctly.
To make this work correctly, make sure the EditText
attributes are set as follows (note the space on digits
):
android:digits="01234 56789"android:inputType="number"android:maxLength="19"
Then here is the TextWatcher
you need. The anonymous class can also be made static since this is independent of the EditText
.
yourTextView.addTextChangedListener(new TextWatcher() { private static final char space = ' '; @Override public void onTextChanged(CharSequence s, int start, int before, int count) { } @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { } @Override public void afterTextChanged(Editable s) { // Remove all spacing char int pos = 0; while (true) { if (pos >= s.length()) break; if (space == s.charAt(pos) && (((pos + 1) % 5) != 0 || pos + 1 == s.length())) { s.delete(pos, pos + 1); } else { pos++; } } // Insert char where needed. pos = 4; while (true) { if (pos >= s.length()) break; final char c = s.charAt(pos); // Only if its a digit where there should be a space we insert a space if ("0123456789".indexOf(c) >= 0) { s.insert(pos, "" + space); } pos += 5; } } });