【问题标题】:how to format credit card expiry date in mm/yy when entered by user用户输入时如何以 mm/yy 格式格式化信用卡到期日期
【发布时间】:2017-08-21 05:04:03
【问题描述】:

我想实现这样的算法:

一旦用户开始为“MM”输入数字,它应该在用户输入“MM”的两位数字后给出“/”,然后,它应该只输入“yy”的最后两位数字。我怎样才能实现这种功能?

【问题讨论】:

标签: android


【解决方案1】:
android:maxLength="5"

并将editText设置为手机,使其显示“/”

android:inputType="phone"

在 textWatcher 上执行此操作 .... 我稍后将验证正确的 mm/yy 月份年份以避免用户输入数据,例如 55/66 max 应该是 12/31 但它应该验证几个月或 30天...

 @Override
    public void afterTextChanged(Editable editable) {


        if (editable.length() > 0 && (editable.length() % 3) == 0) {
            final char c = editable.charAt(editable.length() - 1);
            if ('/' == c) {
                editable.delete(editable.length() - 1, editable.length());
            }
        }
        if (editable.length() > 0 && (editable.length() % 3) == 0) {
            char c = editable.charAt(editable.length() - 1);
            if (Character.isDigit(c) && TextUtils.split(editable.toString(), String.valueOf("/")).length <= 2) {
                editable.insert(editable.length() - 1, String.valueOf("/"));
            }
        }
    }

【讨论】:

    【解决方案2】:

    我只是实现了一个方法,比如 Uber 信用卡日期格式,自动检查、自动完成、自动移动到 CVV 编辑文本。

     <EditText
                android:id="@+id/credit_card_expire_et"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_marginRight="@dimen/activity_horizontal_margin"
                android:layout_weight="1"
                android:hint="MM/YY"
                android:inputType="number"
                android:maxLength="5"
                android:maxLines="1" />
    
        <EditText
            android:id="@+id/credit_card_cvv_et"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginLeft="@dimen/activity_horizontal_margin"
            android:layout_weight="1"
            android:hint="CVV"
            android:inputType="number"
            android:maxLength="3"
            android:maxLines="1" />
    

    .

    @BindView(R.id.credit_card_expire_et)
    EditText creditExpireEt;
    @BindView(R.id.credit_card_cvv_et)
    EditText creditCVVEt;
    
    
    @OnTextChanged(value = R.id.credit_card_expire_et, callback = BEFORE_TEXT_CHANGED)
        void beforeExpireEtChanged() {
            previousLength = creditExpireEt.getText().toString().length();
        }
    
        @OnTextChanged(R.id.credit_card_expire_et)
        void autoFixAndMoveToNext() {
            int length = creditExpireEt.getText().toString().trim().length();
    
            if (previousLength <= length && length < 3) {
                int month = Integer.parseInt(creditExpireEt.getText().toString());
                if (length == 1 && month >= 2) {
                    String autoFixStr = "0" + month + "/";
                    creditExpireEt.setText(autoFixStr);
                    creditExpireEt.setSelection(3);
                } else if (length == 2 && month <= 12) {
                    String autoFixStr = creditExpireEt.getText().toString() + "/";
                    creditExpireEt.setText(autoFixStr);
                    creditExpireEt.setSelection(3);
                } else if (length ==2 && month > 12) {
                    creditExpireEt.setText("1");
                    creditExpireEt.setSelection(1);
                }
            } else if (length == 5) {
                creditCVVEt.requestFocus(); // auto move to next edittext
            }
        }
    

    【讨论】:

    • 这里的previousLength是多少?
    • 它不能正常工作,当你删除/并添加第三个数字时,/将不会被添加
    【解决方案3】:
    private static final String EXP_DATE_REGAX = "(0[1-9]|1[0-2])[0-9]{2}";
    
    if (!edt_expiry_date.getText().toString().isEmpty()) {
    
                        Pattern pattern = Pattern.compile(EXP_DATE_REGAX);
                        Matcher matcher = pattern.matcher(edt_expiry_date.getText().toString());
    
                            if(!matcher.find()){
                                edt_expiry_date.setError("Invalid Expiry Date");
                            }else{
                                Calendar c = Calendar.getInstance();
    
                                int year = c.get(Calendar.YEAR) % 100;
                                int month = c.get(Calendar.MONTH)+1;
    
                                if(Integer.parseInt((edt_expiry_date.getText().toString().substring(2)))>=year){
                                   if(Integer.parseInt((edt_expiry_date.getText().toString().substring(2)))==year){
                                       if(Integer.parseInt((edt_expiry_date.getText().toString().substring(0,2)))>=month){
                                           str_expiry_date = edt_expiry_date.getText().toString();
                                           dialog.dismiss();
                                       }else{
                                           edt_expiry_date.setError("Invalid Expiry Date");
                                       }
                                   }else{
                                       str_expiry_date = edt_expiry_date.getText().toString();
                                       dialog.dismiss();
                                   }
    
    
                                }else{
                                    edt_expiry_date.setError("Invalid Expiry Date");
                                }
    
                               // dialog.dismiss();
    
                        }
    
                    } else {
                        edt_expiry_date.setError("Enter Expiry Date");
                    }
    

    【讨论】:

      【解决方案4】:

      将这些添加到 youredittext.addTextChangedListener

               @Override
               public void onTextChanged(CharSequence s, int start, int before, int count) {
      
                  if (s.length() == 2) {
                      if(start==2 && before==1 && !s.toString().contains("/")){
                          youredittext.setText(""+s.toString().charAt(0));
                          youredittext.setSelection(1);
                      }
                      else {
                          youredittext.setText(s + "/");
                          youredittext.setSelection(3);
                      }
                  }
                }
      

      【讨论】:

      • 请不要只写代码,向OP解释一下
      • 您需要在 textchangelistener 上添加这些行。它工作正常
      【解决方案5】:

      首先将EditText的最大字符数设置为5,如下:

      android:maxLength="5"
      

      并设置为数字editText

      android:inputType="number"
      

      然后在EditText中添加一个onEditTextChangedListener,检测字符数是否变为2且没有从3变为2,如果去掉“/”前的数字,则去掉“/”:

      edit_text.addTextChangedListener(object : TextWatcher {
          override fun afterTextChanged(p0: Editable?) {}
      
          override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}
      
          override fun onTextChanged(p0: CharSequence?, start: Int, removed: Int, added: Int) {
              if (start == 1 && start+added == 2 && p0?.contains('/') == false) {
                  edit_text.setText(p0.toString() + "/")
              } else if (start == 3 && start-removed == 2 && p0?.contains('/') == true) {
                  edit_text.setText(p0.toString().replace("/", ""))
              }
          }
      })
      

      【讨论】:

      • 你能查一下吗,这里有一个类型:editText.setText(editText.getText() += "/"; 就像括号没有闭合一样。
      • 通过这种方法,用户必须同时输入两个数字来替换一个单数才能显示斜线。我认为您可能需要阅读“之前”和“计数”实际代表的内容。 Documentation for onTextChanged 例如,当用户一个接一个地输入字符时,before 将始终为“零”,除非退格一个字符,count 将始终为 1,除非用户选择几个字符并删除它们或粘贴文本。跨度>
      • 不得不对字符限制进行一些裁剪,但希望这能让您很好地理解我的意思。此解决方案的另一个问题更符合“如果用户只是决定输入 118. 或 12018 怎么办。大多数用户会看到“MM/yy”规范,但对于那些没有看到的用户,他们可能会感到非常沮丧很快,EditText 现在无法配合他们想要做的事情。这就是为什么我通常在处理日期时使用选择器。
      • 这将创建一个无限循环:更改 onTextChanged 事件中的文本会一遍又一遍地触发相同的事件......一遍又一遍。
      • @SomeoneSomewhere 编辑了答案,因此不会发生这种情况,但保留了我在其他答案中撕下的其余答案。
      【解决方案6】:
      EditText et_expiry_date= (EditText) findViewById(R.id.et_expiry_date);
      
      et_expiry_date.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) {
          String current = s.toString();
          if (current.length() == 2 && start == 1) {
                  et_expiry_date.setText(current + "/");
                  et_expiry_date.setSelection(current.length() + 1);
          } 
          else if (current.length() == 2 && before == 1) {
              current = current.substring(0, 1);
              et_expiry_date.setText(current);
              et_expiry_date.setSelection(current.length());
          }
      }
      
      @Override
      public void afterTextChanged(Editable s) {}
      });
      

      【讨论】:

        【解决方案7】:

        基于文本的日期输入所需的问题和字符串操作在这里似乎不值得。如果用户回到字符串的开头并开始输入会发生什么?如果用户开始输入错误的格式会发生什么?您必须考虑大量案例,而没有一种很好的方法来控制用户可以输入的内容。在这些情况下,我只会使用 DatePicker like the one in this solution

        如果您有心,您可以保留 EditText,只需设置 onClickListener 以在选中时显示 DatePicker。我建议在上面设置这两个字段:

        android:cursorVisible="false"
        android:focusable="false"
        

        这样,EditText 看起来就不会像可以输入的那样。我唯一的建议或对其他答案的补充是“清除”按钮,因此可以根据需要擦除 EditText 值。为此,只需通过中性按钮添加它,如下所示:

        builder.setView(dialog)
                // Add action buttons
                .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int id) {
                        listener.onDateSet(null, yearPicker.getValue(), monthPicker.getValue(), 0);
                    }
                })
                .setNeutralButton(R.string.clear, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialogInterface, int i) {
                        //check for a month value of -1 in onDateSet to clear current field
                        listener.onDateSet(null, -1, -1, 0);
                    }
                })
                .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int id) {
                        MonthYearPickerFragment.this.getDialog().cancel();
                    }
                });
        

        然后检查是否应该清除该字段,只需执行以下操作:

        @Override
        public void onDateSet(DatePicker datePicker, int i, int i1, int i2) {
            if (i > -1){
                et.setText(i1 + "/" + i);
            } else {
                et.setText("");
            }
        }
        

        【讨论】:

          【解决方案8】:

          在 Kotlin 中的格式类似于

          “月/年”

          你可以用这个,

          et_expire_date.addTextChangedListener(object : TextWatcher {
          
                  override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
                      var working = s.toString()
                      var isValid = true
                      if (working.length == 2 && before == 0) {
                          if (Integer.parseInt(working) < 1 || Integer.parseInt(working) > 12) {
                              isValid = false
                          } else {
                              working += "/"
                              et_expire_date.setText(working)
                              et_expire_date.setSelection(working.length)
                          }
                      } else if (working.length == 5 && before == 0) {
                          val enteredYear = working.substring(3)
                          val currentYear = Calendar.getInstance().get(Calendar.YEAR) % 100//getting last 2 digits of current year i.e. 2018 % 100 = 18
                          if (Integer.parseInt(enteredYear) < currentYear) {
                              isValid = false
                          }
                      } else if (working.length != 5) {
                          isValid = false
                      }
          
                      if (!isValid) {
                          et_expire_date.error = getString(R.string.enter_valid_date_mm_yy)
                      } else {
                          et_expire_date.error = null
                      }
          
                  }
          
                  override fun afterTextChanged(s: Editable) {}
          
                  override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
              })
          

          et_expire_date 是日期输入的编辑文本

          【讨论】:

          • @Vivek Mishra 你面临什么问题?
          • 如果我输入 12 月份,您的 if 语句将不起作用
          • @Vivek Mishra 你的 XML 有这些属性吗? android:digits="0123456789" android:inputType="numberDecimal" android:maxLength="5"
          • 如您在回答中所说,最大长度为 7。
          【解决方案9】:

          使用TextWatcher,例如:

          EditText editText = (EditText) findViewById(R.id.yourEditTextId);
          yourEditText.addTextChangedListener(new TextWatcher() {
          
          public void afterTextChanged(Editable s) {
            // Do what you want here
            String myStr = s.toString();
            // Check if MM and do what you want
          }
          public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
          
          public void onTextChanged(CharSequence s, int start, int before, int count) {}
          });
          

          【讨论】:

            【解决方案10】:

            @Goodlife 的 Kotlin 版本

            override fun afterTextChanged(s: Editable?) {
                            if (s!!.isNotEmpty() && (s.length % 3) == 0) {
                                val c = s[s.length-1]
                                if (c == '/') {
                                    s.delete(s.length-1, s.length)
                                }
                            }
                            if (s.isNotEmpty() && (s.length % 3) == 0) {
                                val c = s[s.length-1]
                                if (Character.isDigit(c) && TextUtils.split(s.toString(), "/").size <= 2) {
                                    s.insert(s.length-1, "/")
                                }
                            }
                        }
            

            【讨论】:

              【解决方案11】:

              简单答案,为 mm/yy 设置长度 5 或为 mm/yyyy 设置长度 7

                  YourEditText.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) {
              
                              int len=s.toString().length();
              
                              if (before == 0 && len == 2)
                                  YourEditText.append("/");
                          }
              
                          @Override
                          public void afterTextChanged(Editable s) {
              
                          }
                      });
              

              【讨论】:

                猜你喜欢
                • 2014-01-03
                • 1970-01-01
                • 2017-09-30
                • 2012-04-28
                • 1970-01-01
                • 2022-11-14
                • 1970-01-01
                • 1970-01-01
                • 2018-08-03
                相关资源
                最近更新 更多