Format credit card in edit text in android

后端 未结 29 1963
耶瑟儿~
耶瑟儿~ 2020-11-30 19:18

How to make EditText accept input in format:

4digit 4digit 4digit 4digit 

I tried Custom format edit text input android to acc

相关标签:
29条回答
  • 2020-11-30 19:39

    Here's a simple and easily customizable solution using the TextWatcher class. It may be assigned to your EditText using the addTextChangedListener() method.

    new TextWatcher() {
        /** Formats the Field to display user-friendly separation of the input values. */
        @Override public final void afterTextChanged(final Editable pEditable) {
            // Declare the separator.
            final char lSeparator      = '-';
            // Declare the length of separated text. i.e. (XXXX-XXXX-XXXX)
            final int  lSeparationSize = 4;
            // Declare the count; tracks the number of allowed characters in a row.
                  int lCount          = 0;
            // Iterate the Characters.
            for(int i = 0; i < pEditable.length(); i++) {
                // Fetch the current character.
                final char c              = pEditable.charAt(i);
                // Is it a usual character. Here, we permit alphanumerics only.
                final boolean lIsExpected = (Character.isDigit(c) || Character.isLetter(c)) && (c != lSeparator);
                // Is the character expected?
                if(lIsExpected) {
                    // Increase the count.
                    lCount++;
                }
                else {
                    // Is it a separator?
                    if(c == lSeparator) {
                        // Reset the count.
                        lCount = 0;
                        // Continue the iteration.
                        continue;
                    }
                }
                // Has the count been exceeded? Is there more text coming?
                if(lCount >= (lSeparationSize + 1) && (i < pEditable.length())) {
                    // Reset the count.
                    lCount = 0;
                    // Insert the separator.
                    pEditable.insert(i, Character.toString(lSeparator));
                    // Increase the iteration count.
                    i++;
                }
            }
        }
        /** Unused overrides. */
        @Override public final void beforeTextChanged(final CharSequence pCharSequence, final int pStart, final int pCount, final int pAfter) { }
        @Override public final void onTextChanged(final CharSequence pCharSequence, final int pStart, final int pBefore, final int pCount) { }
    }
    

    Alternatively, here is a much cleaner implementation based on epool's implementation.

    public final class TextGroupFormattingListener implements TextWatcher {
    
        /* Member Variables. */
        private final int    mGroupLength;
        private final String mSeparator;
        private       String mSource;
    
        /** Constructor. */
        public TextGroupFormattingListener(final String pSeparator, final int pGroupLength) {
            // Initialize Member Variables.
            this.mSeparator   = pSeparator;
            this.mGroupLength = pGroupLength;
            this.mSource      = "";
        }
    
        /** Formats the Field to display user-friendly separation of the input values. */
        @Override public final void afterTextChanged(final Editable pEditable) {
            // Fetch the Source.
            String lSource = pEditable.toString();
            // Has the text changed?
            if (!this.getSource().equals(lSource)) {
                // Remove all of the existing Separators.
                lSource = lSource.replace(this.getSeparator(), "");
                // Allocate a StringBuilder.
                StringBuilder lStringBuilder = new StringBuilder();
                // Iterate across the Source String, which contains the raw user input.
                for(int i = 0; i < lSource.length(); i++) {
                    // Have we exceeded the GroupLength?
                    if(i > 0 && i % this.getGroupLength() == 0) {
                        // Append the separator.
                        lStringBuilder.append(this.getSeparator());
                    }
                    // Append the user's character data.
                    lStringBuilder.append(lSource.charAt(i));
                }
                // Track changes to the Source.
                this.setSource(lStringBuilder.toString());
                // Replace the contents of the Editable with this new String.
                pEditable.replace(0, pEditable.length(), this.getSource());
            }
        }
    
        /** Unused overrides. */
        @Override public final void beforeTextChanged(final CharSequence pCharSequence, final int pStart, final int pCount, final int pAfter) { }
        @Override public final void onTextChanged(final CharSequence pCharSequence, final int pStart, final int pBefore, final int pCount)    { }
    
        public final int getGroupLength() {
            return this.mGroupLength;
        }
    
        public final String getSeparator() {
            return this.mSeparator;
        }
    
        private final void setSource(final String pSource) {
            this.mSource = pSource;
        }
    
        private final String getSource() {
            return this.mSource;
        }
    
    }
    
    0 讨论(0)
  • 2020-11-30 19:42

    I just did the next implementation and works well for me, even with pasting and typing new text in any position of the EditText.

    Gist file

    /**
     * Text watcher for giving "#### #### #### ####" format to edit text.
     * Created by epool on 3/14/16.
     */
    public class CreditCardFormattingTextWatcher implements TextWatcher {
    
        private static final String EMPTY_STRING = "";
        private static final String WHITE_SPACE = " ";
        private String lastSource = EMPTY_STRING;
    
        @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) {
            String source = s.toString();
            if (!lastSource.equals(source)) {
                source = source.replace(WHITE_SPACE, EMPTY_STRING);
                StringBuilder stringBuilder = new StringBuilder();
                for (int i = 0; i < source.length(); i++) {
                    if (i > 0 && i % 4 == 0) {
                        stringBuilder.append(WHITE_SPACE);
                    }
                    stringBuilder.append(source.charAt(i));
                }
                lastSource = stringBuilder.toString();
                s.replace(0, s.length(), lastSource);
            }
        }
    
    }
    

    Usage: editText.addTextChangedListener(new CreditCardFormattingTextWatcher());

    0 讨论(0)
  • 2020-11-30 19:43
    int          keyDel;
    String       a;
    String       a0;
    int          isAppent = 0;
    final String ch       = " ";
    
    private void initListner() {
    
    
        txtCreditNumber.addTextChangedListener(new TextWatcher() {
    
            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
    
                boolean flag = true;
                if (s.length() > 19) {
                    txtCreditNumber.setText(a0);
                    txtCreditNumber.setSelection(txtCreditNumber.getText().length());
                    return;
                }
                String eachBlock[] = s.toString().split(ch);
                for(int i = 0; i < eachBlock.length; i++) {
                    if (eachBlock[i].length() > 4) {
                        flag = false;
                    }
                }
                if (a0.length() > s.toString().length()) {
                    keyDel = 1;
                }
                if (flag) {
                    if (keyDel == 0) {
    
                        if (((txtCreditNumber.getText().length() + 1) % 5) == 0) {
    
                            if (s.toString().split(ch).length <= 3) {
                                isAppent = 1;
                                txtCreditNumber.setText(s + ch);
                                isAppent = 0;
                                txtCreditNumber.setSelection(txtCreditNumber.getText().length());
                                a = txtCreditNumber.getText().toString();
                                return;
                            }
                        }
                        if (isAppent == 0) {
                            String str = s.toString();
                            if (str.lastIndexOf(ch) == str.length() - 1) {
                                str = str.substring(0, str.lastIndexOf(ch));
                                keyDel = 1;
                                txtCreditNumber.setText(str);
                                keyDel = 0;
                                txtCreditNumber.setSelection(txtCreditNumber.getText().length());
                                a = txtCreditNumber.getText().toString();
                                return;
                            }
                        }
    
                    }
                    else {
                        String str = s.toString();
                        if (str.length() > 0 && str.lastIndexOf(ch) == str.length() - 1) {
                            str = str.substring(0, str.lastIndexOf(ch));
                            keyDel = 1;
                            txtCreditNumber.setText(str);
                            keyDel = 0;
                            txtCreditNumber.setSelection(txtCreditNumber.getText().length());
                            a = txtCreditNumber.getText().toString();
                            return;
                        }
                        else {
                            a = txtCreditNumber.getText().toString();
                            keyDel = 0;
                        }
                    }
    
                }
                else {
                    String str = s.toString();
                    str = str.substring(0, str.length() - 1) + ch + str.substring(str.length() - 1, str.length());
    
                    a = str;
                    txtCreditNumber.setText(a);
                    txtCreditNumber.setSelection(txtCreditNumber.getText().length());
                }
    
            }
    
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
                // TODO Auto-generated method stub
                a0 = s.toString();
            }
    
            @Override
            public void afterTextChanged(Editable s) {
            }
        });
    }
    
    0 讨论(0)
  • 2020-11-30 19:44

    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;
                }
            }
        });
    
    0 讨论(0)
  • 2020-11-30 19:46

    I know this question is a bit old but I need an implemantation of this for IBAN's and not satisfied with the given answers. So I wrote some code for this. But it takes the "pattern" and "divider" as parameters so it can be use for credit card numbers too.

    This is the extended text watcher class.

    import android.text.Editable;
    import android.text.TextWatcher;
    import android.widget.EditText;
    
    public class IbanTextWatcher implements TextWatcher {
    
        private int[] pattern;
        private String divider;
        private String before;
        private EditText field;
        private boolean dividerDeleted;
    
    
        public IbanTextWatcher(int[] pattern, String divider, EditText field) {
            this.divider = divider;
            this.pattern = pattern;
            this.field = field;
        }
    
    
        @Override
        public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
            before = charSequence.toString();
    
            if (!String.valueOf(charSequence).equals("") && charSequence.length() > i) {
                if (String.valueOf(before.charAt(i)).equals(getDivider())) {
                    dividerDeleted = true;
                } else {
                    dividerDeleted = false;
                }
            }
        }
    
        @Override
        public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
    
        }
    
        @Override
        public void afterTextChanged(Editable editable) {
    
            String input = editable.toString().replaceAll("\\s", "");
            StringBuilder output = new StringBuilder();
            boolean error = false;
            int currentIndex = 0;
            int cursorPosition = getField().getSelectionStart();
            int lengthBefore;
            int currentPatternMember = 0;
    
            //prevent user to delete the divider
            if (dividerDeleted && cursorPosition != getField().getText().length()) {
                getField().setText(getBefore());
                getField().setSelection(cursorPosition + 1);
                return;
            } else if (input.equals(getBefore().replaceAll("\\s", ""))) {
                return;
            }
    
            for (int i = 0; i < getPattern().length; i++) {
                error = false;
                currentPatternMember = getPattern()[i];
                try {
                    output.append(input.substring(currentIndex, currentIndex + currentPatternMember));
                } catch (StringIndexOutOfBoundsException e) {
                    error = true;
                }
    
                if (!error) {
                    if (i != getPattern().length - 1) {
                        output.append(getDivider());
                    }
                    currentIndex += currentPatternMember;
                } else {
                    break;
                }
            }
    
            if (error) {
                output.append(input.substring(currentIndex, input.length()));
            } 
    
            cursorPosition = getField().getSelectionStart();
            lengthBefore = getBefore().length();
            getField().setText(output.toString());
    
            if (cursorPosition != lengthBefore && cursorPosition != lengthBefore + 1) {
                getField().setSelection(cursorPosition);
            } else {
                getField().setSelection(getField().getText().length());
            }
        }
    
        public int[] getPattern() {
            return pattern;
        }
    
        public String getDivider() {
            return divider;
        }
    
        public String getBefore() {
            return before;
        }
    
        public EditText getField() {
            return field;
        }
    }
    

    And this is how I use it:

    int[] pattern = {2,4,4,4,4,4,2}; // 
    iban.addTextChangedListener(new IbanTextWatcher(pattern, " ", iban); //here iban is my edittext field
    

    By the way, I set the max length of the field in xml.

    0 讨论(0)
  • 2020-11-30 19:47

    Example on github.com

    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.

    0 讨论(0)
提交回复
热议问题