Intereting Posts
Android – выбор фокус на растровое изображение Imageloader загружает только изображения в списке после того, как listitem ушел с экрана Как передать предварительный просмотр камеры на поверхность, созданный MediaCodec.createInputSurface ()? Настроить изображение (фото) на Chromecast Никаких определений для устройств Kindle Fire, доступных в Android SDK Manager Зарегистрировать приложение по умолчанию для настраиваемого типа файла Android, Intent.FLAG_ACTIVITY_CLEAR_TOP, похоже, не работает? Приглашение виджета Android для разблокировки InetAddress.getLocalHost (). GetHostAddress () возвращает 127.0.0.1 в Android Google Play Store: страница моего приложения не отображает значки и значки лидеров и достижений Ионные: медленные переходы в установленном приложении для Android Как запустить файл apk онлайн? Gradle: DefaultAndroidSourceDirectorySet to File с использованием метода toString () устарел Как добавить новую активность в существующий проект в Android Studio? Любой способ скрыть элементы из webview? (андроид)

Дата окончания форматирования в формате mm / yy

Привет, я пишу edittext, в котором я хочу дату истечения срока действия кредитной карты в формате MM / YY. Алгоритм, который я хочу реализовать, выглядит следующим образом: если пользователь вводит что-либо от 2 до 9. Я меняю ввод текста на 02 / на 09 / Если пользователь вводит 1, то я жду следующей цифры и проверю, является ли месяц значения int Если меньше 12. Вот мой код для этого.

@Override public void afterTextChanged(Editable s) { String input = s.toString(); if (s.length() == 1) { int month = Integer.parseInt(input); if (month > 1) { mExpiryDate.setText("0" + mExpiryDate.getText().toString() + "/"); mExpiryDate.setSelection(mExpiryDate.getText().toString().length()); mSeperator = true; } } else if (s.length() == 2) { int month = Integer.parseInt(input); if (month <= 12) { mExpiryDate.setText(mExpiryDate.getText().toString() + "/"); mExpiryDate.setSelection(mExpiryDate.getText().toString().length()); mSeperator = true; } } else { } } 

Это работает нормально, пока я не нажму кнопку программной клавиши. Обратный слэш никогда не возвращается. Причина в том, что второе условие всегда выполняется. Я смущен тем, как это решить. Как обрабатывать кнопку «Назад» внутри aftertextchanged? Пожалуйста помоги.

См. Мой комментарий выше, чтобы понять вашу проблему. Вы можете использовать это, чтобы проверить ввод пользователя с помощью текстового элемента:

 SimpleDateFormat formatter = new SimpleDateFormat("MM/yy", Locale.GERMANY); Calendar expiryDateDate = Calendar.getInstance(); try { expiryDateDate.setTime(formatter.parse(mExpiryDate.getText().toString())); } catch (ParseException e) { //not valid } // expiryDateDate has a valid date from the user 

Так что в полном объеме это было бы:

 String lastInput =""; @Override public void afterTextChanged(Editable s) { String input = s.toString(); SimpleDateFormat formatter = new SimpleDateFormat("MM/yy", Locale.GERMANY); Calendar expiryDateDate = Calendar.getInstance(); try { expiryDateDate.setTime(formatter.parse(input)); } catch (ParseException e) { if (s.length() == 2 && !lastInput.endsWith("/")) { int month = Integer.parseInt(input); if (month <= 12) { mExpiryDate.setText(mExpiryDate.getText().toString() + "/"); } }else if (s.length() == 2 && lastInput.endsWith("/")) { int month = Integer.parseInt(input); if (month <= 12) { mExpiryDate.setText(mExpiryDate.getText().toString().subStr(0,1); } } lastInput = mExpiryDate.getText().toString(); //because not valid so code exits here return; } // expiryDateDate has a valid date from the user // Do something with expiryDateDate here } 

Наконец, полное решение:

 String input = s.toString(); SimpleDateFormat formatter = new SimpleDateFormat("MM/yy", Locale.GERMANY); Calendar expiryDateDate = Calendar.getInstance(); try { expiryDateDate.setTime(formatter.parse(input)); } catch (ParseException e) { } catch (java.text.ParseException e) { if (s.length() == 2 && !mLastInput.endsWith("/")) { int month = Integer.parseInt(input); if (month <= 12) { mExpiryDate.setText(mExpiryDate.getText().toString() + "/"); mExpiryDate.setSelection(mExpiryDate.getText().toString().length()); } }else if (s.length() == 2 && mLastInput.endsWith("/")) { int month = Integer.parseInt(input); if (month <= 12) { mExpiryDate.setText(mExpiryDate.getText().toString().substring(0,1)); mExpiryDate.setSelection(mExpiryDate.getText().toString().length()); } else { mExpiryDate.setText(""); mExpiryDate.setSelection(mExpiryDate.getText().toString().length()); Toast.makeText(getApplicationContext(), "Enter a valid month", Toast.LENGTH_LONG).show(); } } else if (s.length() == 1){ int month = Integer.parseInt(input); if (month > 1) { mExpiryDate.setText("0" + mExpiryDate.getText().toString() + "/"); mExpiryDate.setSelection(mExpiryDate.getText().toString().length()); } } else { } mLastInput = mExpiryDate.getText().toString(); return; 

Решение @alex выше было хорошим, но в нескольких случаях это не удавалось. Например, когда вы пытаетесь удалить косую черту, потому что она никогда не достигает значения if (s.length () == 2 && mLastInput.endsWith ("/")), когда вы пытаетесь удалить косую черту, она будет иметь значение в if (s.length () == 2 &&! MLastInput.endsWith ("/"), и поэтому это создаст иллюзию, что косая черта не удаляется.

Он также терпит неудачу, если пользователь завершит дату, то есть 08/16, а затем вернет свой курсор в месяц и удалит, он также завершится неудачно, если может быть какая-то дата, например, 0/1. Поэтому я только что внесли некоторые изменения в решение @ alex.

 //Make sure for mExpiryDate to be accepting Numbers only boolean isSlash = false; //class level initialization private void formatCardExpiringDate(Editable s){ String input = s.toString(); String mLastInput = ""; SimpleDateFormat formatter = new SimpleDateFormat("MM/yy", Locale.ENGLISH); Calendar expiryDateDate = Calendar.getInstance(); try { expiryDateDate.setTime(formatter.parse(input)); } catch (java.text.ParseException e) { if (s.length() == 2 && !mLastInput.endsWith("/") && isSlash) { isSlash = false; int month = Integer.parseInt(input); if (month <= 12) { mExpiryDate.setText(mExpiryDate.getText().toString().substring(0, 1)); mExpiryDate.setSelection(mExpiryDate.getText().toString().length()); } else { s.clear(); mExpiryDate.setText(""); mExpiryDate.setSelection(mExpiryDate.getText().toString().length()); Toast.makeText(context.getApplicationContext(), "Enter a valid month", Toast.LENGTH_LONG).show(); } }else if (s.length() == 2 && !mLastInput.endsWith("/") && !isSlash) { isSlash = true; int month = Integer.parseInt(input); if (month <= 12) { mExpiryDate.setText(mExpiryDate.getText().toString() + "/"); mExpiryDate.setSelection(mExpiryDate.getText().toString().length()); }else if(month > 12){ edCardDate.setText(""); mExpiryDate.setSelection(mExpiryDate.getText().toString().length()); s.clear(); _toastMessage("invalid month", context); } } else if (s.length() == 1) { int month = Integer.parseInt(input); if (month > 1 && month < 12) { isSlash = true; mExpiryDate.setText("0" + mExpiryDate.getText().toString() + "/"); mExpiryDate.setSelection(mExpiryDate.getText().toString().length()); } } mLastInput = mExpiryDate.getText().toString(); return; } } //wrap method formatCardExpiringDate around try catch or wrap the entire code in try catch, catching NumberFormateException. To take care of situations when s.length() == 2 and there is aa number in from of the slash @Override public void afterTextChanged(Editable s) { try{ formatCardExpiringDate(s) }catch(NumberFormatException e){ s.clear(); //Toast message here.. Wrong date formate } } 

Я бы снова проверил месяц, когда пользователь нажимал на submit, чтобы быть уверенным.

 String expdate[] = mExpiryDate.getText().toString().split("/"); if(Integer.ParseInt(expDate[0]) > 12){ // Toast message "wrong date format".... } 

Надеюсь, это поможет….

Может быть, вы можете так:

 boolean validateCardExpiryDate(String expiryDate) { return expiryDate.matches("(?:0[1-9]|1[0-2])/[0-9]{2}"); } 

Который переводится как:

(Не захватывающая группа?): 0, затем 1-9 или 1, затем 0-2, а затем «/», а затем 0-9, дважды. … поэтому эта версия требует нулевых месяцев (01 – 12). Добавить ? После первого 0, чтобы предотвратить это.

Надеюсь, это поможет вам .. !!!

TextWatchers используются для обновления внешнего свойства (например, в вашем ViewModel ) каждый раз при редактировании.

TextWatchers не должны использоваться для изменения собственного текста EditText .

Для ввода форматирования вы должны использовать InputFilter вместо TextWatcher . Попробуйте следующее:

Включите в свой проект следующий класс:

 /** * InputFilter to ensure user enters valid expiry date in a credit card. * User is only allowed to type from beginning-to-end without copy-pasting or inserting characters in the middle. * The user may enter any month 01 -> 12. * The user can enter, at minimum, the current year or any year that follows. * * Note: `inputType` of the EditText should be `number` and `digits` should be `0123456789/`. * * Created by WKS on 30/07/2017 (Licensed under GNU Public License - original author must be credited) */ public class CreditCardExpiryInputFilter implements InputFilter { private final String currentYearLastTwoDigits; public CreditCardExpiryInputFilter() { currentYearLastTwoDigits = new SimpleDateFormat("yy", Locale.US).format(new Date()); } public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) { //do not insert if length is already 5 if (dest != null & dest.toString().length() == 5) return ""; //do not insert more than 1 character at a time if (source.length() > 1) return ""; //only allow character to be inserted at the end of the current text if (dest.length() > 0 && dstart != dest.length()) return ""; //if backspace, skip if (source.length() == 0) { return source; } //At this point, `source` is a single character being inserted at `dstart`. //`dstart` is at the end of the current text. final char inputChar = source.charAt(0); if (dstart == 0) { //first month digit if (inputChar > '1') return ""; } if (dstart == 1) { //second month digit final char firstMonthChar = dest.charAt(0); if (firstMonthChar == '0' && inputChar == '0') return ""; if (firstMonthChar == '1' && inputChar > '2') return ""; } if (dstart == 2) { final char currYearFirstChar = currentYearLastTwoDigits.charAt(0); if (inputChar < currYearFirstChar) return ""; return "/".concat(source.toString()); } if (dstart == 4){ final String inputYear = ""+dest.charAt(dest.length()-1)+source.toString(); if (inputYear.compareTo(currentYearLastTwoDigits) < 0) return ""; } return source; } } 

Примените CreditCardExpiryInputFilter к вашему EditText :

 EditText expiryEditText = findViewById(this, R.id.edittext_expiry_date); expiryEditText.setFilters(new InputFilter[]{new CreditCardExpiryInputFilter()}); 

В xml установите для параметра inputType значение number и digits 0123456789/ :

 <EditText android:id="@+id/edittext_expiry_date" android:layout_width="match_parent" android:layout_height="wrap_content" android:inputType="number" android:digits="0123456789/" />