【问题标题】:Custom format edit text input android to accept credit card number自定义格式编辑文本输入android接受信用卡号
【发布时间】:2011-08-22 07:19:05
【问题描述】:

如何让编辑文本接受格式输入

4digitnumber-4dignumber-4dignumber-4dignumber   

代码

text.addTextChangedListener(new TextWatcher() {
    int len = 0;
    String string ;
    @Override

    public void afterTextChanged(Editable s) {

        text.setOnKeyListener(new OnKeyListener()
        {   public boolean onKey(View v, int keyCode, KeyEvent event)
            {              
                    if (keyCode == KeyEvent.KEYCODE_DEL)
                    {

                    }
                    else{

                        string = text.getText().toString();
                        len = string.length()+1;
                        if(len%5==0){text.append("-");}

             }

                return false;      }   });
    }
});

在添加时工作正常,但删除或编辑会导致问题。

【问题讨论】:

标签: android android-layout android-widget


【解决方案1】:

现在这适用于所有删除/编辑操作的软/硬键盘。 tx 4 你的帮助..

package com.and;

import android.app.Activity;
import android.app.AlertDialog;
import android.inputmethodservice.KeyboardView;
import android.os.Bundle;
import android.telephony.PhoneNumberFormattingTextWatcher;
import android.text.Editable;
import android.text.Selection;
import android.text.Spannable;
import android.text.TextWatcher;
import android.text.format.Formatter;
import android.text.method.NumberKeyListener;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnKeyListener;
import android.widget.EditText;
import android.widget.Toast;

public class ccformat extends Activity {

    String a;
    int keyDel;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        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) {
            }
        });
    }
}

【讨论】:

  • 但是对于我的代码,当我按下返回键时,代码崩溃了......上面的代码也没有删除空格。
【解决方案2】:

这是有效的:

public class EditTextSample extends Activity {
    // This regexp has to be improved, it does not detect case where you have
    // more than 4 digits in a middle group like: 1234-12345-123
    static final Pattern CODE_PATTERN = Pattern.compile("([0-9]{0,4})|([0-9]{4}-)+|([0-9]{4}-[0-9]{0,4})+");

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.edit_text_sample);

        final EditText editText = (EditText) findViewById(R.id.input);
        editText.addTextChangedListener(new TextWatcher() {

            @Override
            public void afterTextChanged(Editable s) {
                Log.w("", "input" + s.toString());

                if (s.length() > 0 && !CODE_PATTERN.matcher(s).matches()) {
                    String input = s.toString();
                    String numbersOnly = keepNumbersOnly(input);
                    String code = formatNumbersAsCode(numbersOnly);

                    Log.w("", "numbersOnly" + numbersOnly);
                    Log.w("", "code" + code);

                    editText.removeTextChangedListener(this);
                    editText.setText(code);
                    // You could also remember the previous position of the cursor
                    editText.setSelection(code.length());
                    editText.addTextChangedListener(this);
                }
            }

            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
            }

            private String keepNumbersOnly(CharSequence s) {
                return s.toString().replaceAll("[^0-9]", ""); // Should of course be more robust
            }

            private String formatNumbersAsCode(CharSequence s) {
                int groupDigits = 0;
                String tmp = "";
                for (int i = 0; i < s.length(); ++i) {
                    tmp += s.charAt(i);
                    ++groupDigits;
                    if (groupDigits == 4) {
                        tmp += "-";
                        groupDigits = 0;
                    }
                }
                return tmp;
            }
        });
    }
}

【讨论】:

  • 不错的解决方案。虽然在进行更改时锁定观察者的较低开销方法只是提供一个编辑布尔值。这就是谷歌在他们的 TextWatcher 实现中所做的。不过,+1。
  • 确实,如果按照谷歌的方法更好,我没有考虑过:/(见那里:grepcode.com/file/repository.grepcode.com/java/ext/…
  • tx..有没有办法在每次编辑后将光标设置在特定位置,文本的末尾以在编辑文本小部件中指定。?
  • editText.setSelection(code.length());可以。但是您可以在使用 editText.getSelectionStart() 设置文本之前简单地记住位置
  • 这个解决方案会导致递归和堆栈溢出
【解决方案3】:

如果您想仅对数字进行视觉分组,但又不想更改添加破折号的EditText 的值,则可以使用Span 方法:

EditText editText = findViewById(R.id.editText);
editText.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 editable) {
        Object[] paddingSpans = editable.getSpans(0, editable.length(), DashSpan.class);
        for (Object span : paddingSpans) {
            editable.removeSpan(span);
        }

        addSpans(editable);
    }

    private static final int GROUP_SIZE = 4;

    private void addSpans(Editable editable) {

        final int length = editable.length();
        for (int i = 1; i * (GROUP_SIZE) < length; i++) {
            int index = i * GROUP_SIZE;
            editable.setSpan(new DashSpan(), index - 1, index,
                    Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
        }
    }
});

DashSpan 类如下所示:

/**
 * A {@link ReplacementSpan} used for spacing in {@link android.widget.EditText}
 * to space things out. Adds '-'s
 */
public class DashSpan extends ReplacementSpan {

    @Override
    public int getSize(@NonNull Paint paint, CharSequence text, int start, int end, FontMetricsInt fm) {
        float padding = paint.measureText("-", 0, 1);
        float textSize = paint.measureText(text, start, end);
        return (int) (padding + textSize);
    }

    @Override
    public void draw(@NonNull Canvas canvas, CharSequence text, int start, int end, float x, int top, int y,
                     int bottom, @NonNull Paint paint) {
        canvas.drawText(text.subSequence(start, end) + "-", x, y, paint);
    }
}

这样,您将使用破折号直观地进行分组,但getText() 将返回没有任何分组的文本。

要强制只使用数字,您可以将属性android:digits="0123456789"android:inputType="number" 添加到EditText

本方案基于this库的代码。

【讨论】:

    【解决方案4】:

    在我的例子中,下面的代码工作正常。

    editTextCreditCard.addTextChangedListener(new FourDigitCardFormatWatcher());
    

    TextWatcher 添加自定义类。

    public class FourDigitCardFormatWatcher implements 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) {
                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());
                    }
                }
                if (s.length() > 0 && (s.length() % 5) == 0) {
                    char c = s.charAt(s.length() - 1);
                    if (Character.isDigit(c) && TextUtils.split(s.toString(), String.valueOf(space)).length <= 3) {
                        s.insert(s.length() - 1, String.valueOf(space));
                    }
                }
            }
        }
    

    希望这会对你有所帮助。

    【讨论】:

      【解决方案5】:

      它适用于所有情况,当您插入或删除字符时,格式将始终正确。确保你设置

      android:inputType="number"
      

      /

      myEditText.addTextChangedListener(new TextWatcher() {
              private final String space = "-"; // you can change this to whatever you want
              private final Pattern pattern = Pattern.compile("^(\\d{4}"+space+"{1}){0,3}\\d{1,4}$"); // check whether we need to modify or not
              @Override
              public void onTextChanged(CharSequence s, int st, int be, int count) {
                  String currentText = myEditText.getText().toString();
                  if (currentText.isEmpty() || pattern.matcher(currentText).matches())
                      return; // no need to modify
                  String numbersOnly = currentText.trim().replaceAll("[^\\d.]", "");; // remove everything but numbers
                  String formatted = "";
                  for(int i = 0; i < numbersOnly.length(); i += 4)
                      if (i + 4 < numbersOnly.length())
                          formatted += numbersOnly.substring(i,i+4)+space;
                      else
                          formatted += numbersOnly.substring(i);
                  myEditText.setText(formatted);
                  myEditText.setSelection(myEditText.getText().toString().length());
              }
              @Override
              public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
      
              @Override
              public void afterTextChanged(Editable e) {}
      });
      

      【讨论】:

      • 干得好,但不要在 for 循环中连接字符串,使用 StringBuilder `formatted.append(numbersOnly.substring(i, i + 4)).append(space);`
      • 找了2个小时终于找到了,谢谢哥们!!
      【解决方案6】:

      在我看来,这里提供的答案不适用于删除、从中间操作等中删除。 这是我的代码。它不限制输入的长度,但似乎可以进行各种插入和删除:

      import android.text.Editable;
      import android.text.TextWatcher;
      import android.view.KeyEvent;
      import android.view.View;
      import android.widget.EditText;
      
      public class HyphenDelimitTextWatcher implements TextWatcher {
          EditText mEditText;
          boolean mInside = false;
          boolean mWannaDeleteHyphen = false;
          boolean mKeyListenerSet = false;
          final static String MARKER = "|"; // filtered in layout not to be in the string
      
          @Override
          public void beforeTextChanged(CharSequence s, int start, int count, int after) {
              if(!mKeyListenerSet) {
                  mEditText.setOnKeyListener(new View.OnKeyListener() {
                      @Override
                      public boolean onKey(View v, int keyCode, KeyEvent event) {
                          try {
                              mWannaDeleteHyphen = (keyCode == KeyEvent.KEYCODE_DEL
                                      && mEditText.getSelectionEnd() - mEditText.getSelectionStart() <= 1
                                      && mEditText.getSelectionStart() > 0
                                      && mEditText.getText().toString().charAt(mEditText.getSelectionEnd() - 1) == '-');
                          } catch (IndexOutOfBoundsException e) {
                              // never to happen because of checks
                          }
                          return false;
                      }
                  });
                  mKeyListenerSet = true;
              }
          }
      
          @Override
          public void onTextChanged(CharSequence s, int start, int before, int count) {
              if (mInside) // to avoid recursive calls
                  return;
              mInside = true;
      
              int currentPos = mEditText.getSelectionStart();
              String string = mEditText.getText().toString().toUpperCase();
              String newString = makePrettyString(string);
      
              mEditText.setText(newString);
              try {
                  mEditText.setSelection(getCursorPos(string, newString, currentPos, mWannaDeleteHyphen));
              } catch (IndexOutOfBoundsException e) {
                  mEditText.setSelection(mEditText.length()); // last resort never to happen
              }
      
              mWannaDeleteHyphen = false;
              mInside = false;
          }
      
          @Override
          public void afterTextChanged(Editable s) {
          }
      
          private String makePrettyString(String string) {
              String number = string.replaceAll("-", "");
              boolean isEndHyphen = string.endsWith("-") && (number.length()%4 == 0);
              return number.replaceAll("(.{4}(?!$))", "$1-") + (isEndHyphen ?"-":"");
          }
      
          private int getCursorPos(String oldString, String newString, int oldPos, boolean isDeleteHyphen) {
              int cursorPos = newString.length();
              if(oldPos != oldString.length()) {
                  String stringWithMarker = oldString.substring(0, oldPos) + MARKER + oldString.substring(oldPos);
      
                  cursorPos = (makePrettyString(stringWithMarker)).indexOf(MARKER);
                  if(isDeleteHyphen)
                      cursorPos -= 1;
              }
              return cursorPos;
          }
      
          public HyphenDelimitTextWatcher(EditText editText) {
              mEditText = editText;
          }
      }
      

      用法:

          mSomeEditText.addTextChangedListener(new HyphenDelimitTextWatcher(mSomeEditText));
      

      【讨论】:

        【解决方案7】:

        如果你需要这个效果,你可以在EditText中使用这个code

        【讨论】:

          【解决方案8】:

          这是一个格式正则表达式,用于以 XXXX XXXX XXXX XXXX 格式显示卡片详细信息

          etCreditCardNumber.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) {
                          etCreditCardNumber.setFloatingLabel(MaterialEditText.FLOATING_LABEL_HIGHLIGHT);
          
                          String initial = s.toString();
                          // remove all non-digits characters
                          String processed = initial.replaceAll("\\D", "");
          
                          // insert a space after all groups of 4 digits that are followed by another digit
                          processed = processed.replaceAll("(\\d{4})(?=\\d)(?=\\d)(?=\\d)", "$1 ");
          
                          //Remove the listener
                          etCreditCardNumber.removeTextChangedListener(this);
          
                          int index = etCreditCardNumber.getSelectionEnd();
          
                          if (index == 5 || index == 10 || index == 15)
                              if (count > before)
                                  index++;
                              else
                                  index--;
          
                          //Assign processed text
                          etCreditCardNumber.setText(processed);
          
                          try {
                              etCreditCardNumber.setSelection(index);
                          } catch (Exception e) {
                              e.printStackTrace();
                              etCreditCardNumber.setSelection(s.length() - 1);
                          }
                          //Give back the listener
                          etCreditCardNumber.addTextChangedListener(this);
                      }
          
                      @Override
                      public void afterTextChanged(Editable s) {
          
                      }
                  });
          

          【讨论】:

          • 你在发帖前测试过这个吗?
          • @KishanSolanki 是的,我在我的一个项目中使用它并在此处粘贴副本。我无法再访问它,但它工作正常。
          猜你喜欢
          • 2012-08-01
          • 1970-01-01
          • 2017-05-24
          • 2020-06-22
          • 2023-03-23
          • 1970-01-01
          • 2022-01-14
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多