Как разрешить формат mm/yyyy в edittext для ввода данных кредитной/дебетовой карты

У меня есть activity, куда добавляются данные кредитной/дебетовой карты. В настоящее время мой код позволяет добавлять дату и месяц в формате MM/YY. Но мне нужен год в формате 4 цифр MM/YYYY. Добавление разделителя '/' устанавливается после 2-й цифры. Поэтому, если я увеличу общее количество цифр, я получу делитель после каждой второй цифры. Как это исправить?

Carddetails.java:

public class CardDetailsActivity extends AppCompatActivity implements TextWatcher {
    private static final int CARD_NUMBER_TOTAL_SYMBOLS = 19; // size of pattern 0000-0000-0000-0000
    private static final int CARD_NUMBER_TOTAL_DIGITS = 16; // max numbers of digits in pattern: 0000 x walknew2
    private static final int CARD_NUMBER_DIVIDER_MODULO = 5; // means divider position is every 5th symbol beginning with walknew4
    private static final int CARD_NUMBER_DIVIDER_POSITION = CARD_NUMBER_DIVIDER_MODULO - 1; // means divider position is every 4th symbol beginning with 0
    private static final char CARD_NUMBER_DIVIDER = '-';
    @BindView(R.id.cardno)
    EditText cardno;
    @BindView(R.id.cardDateEditText)
    EditText cardDateEditText;
    @BindView(R.id.cardCVCEditText)
    EditText cardCVCEditText;
    SharedPreferences pref;
    SharedPreferences.Editor editor;
    private static final int CARD_DATE_TOTAL_SYMBOLS = 7; // size of pattern MM/YY
    private static final int CARD_DATE_TOTAL_DIGITS = 6; // max numbers of digits in pattern: MM + YY
    private static final int CARD_DATE_DIVIDER_MODULO = 3; // means divider position is every 3rd symbol beginning with walknew4
    private static final int CARD_DATE_DIVIDER_POSITION = CARD_DATE_DIVIDER_MODULO - 1; // means divider position is every 2nd symbol beginning with 0
    private static final char CARD_DATE_DIVIDER = '/';

    private static final int CARD_CVC_TOTAL_SYMBOLS = 3;
    String card_date, card_year, card_month, card_cvv, card_num, user_id, card_type = "debitcard";

    @BindView(R.id.btn_add_card)
    Button btn_add_card;
    @BindView(R.id.btn_back)
    Button btn_back;
    Context context;
    ProgressDialog progressDialog;
    ApiService apiService;
    String driverid, id, usertype, c_id, booking_id;
    EditText card_numm, card_yearm, card_cvvm;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_card_details);
        ButterKnife.bind(this);
        context = CardDetailsActivity.this;
        Log.e("TAG", "Inside Card Details Activity:");
        apiService = RetrofitSingleton.getApiService();
        usertype = PrefConnect.readString(CardDetailsActivity.this, PrefConnect.USERTYPE, "");
        pref = getApplicationContext().getSharedPreferences("MyPref", 0);
        editor = pref.edit();

        id = pref.getString("driver_id", "");
        Log.e("driver_id", id);
        try {
            if (getIntent() != null) {

                driverid = getIntent().getStringExtra("Driverid");
                booking_id = getIntent().getStringExtra("bookingid");


            }

        } catch (Exception e) {
            e.printStackTrace();
            Log.e("paymentact", e.getMessage());

        }


        cardno.getText().toString().trim();
        getWindow().setSoftInputMode(
                WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);

        cardno.addTextChangedListener(this);
        cardDateEditText.addTextChangedListener(this);

        card_numm = (EditText) findViewById(R.id.cardno);
        card_yearm = (EditText) findViewById(R.id.cardDateEditText);
        card_cvvm = (EditText) findViewById(R.id.cardCVCEditText);


    }

    @OnClick({R.id.btn_add_card, R.id.btn_back})
    public void OnClick(View view) {
        switch (view.getId()) {

            case R.id.btn_back:
                finish();
                break;

            case R.id.btn_add_card:
                View view1 = getCurrentFocus();
                Log.e("TAG", "Inside Card Details Activity Button Add Card ");
                Validation();

                break;
        }
    }





    private boolean isInputCorrect(Editable s, int size, int dividerPosition, char divider) {
        boolean isCorrect = s.length() <= size;
        for (int i = 0; i < s.length(); i++) {
            if (i > 0 && (i + 1) % dividerPosition == 0) {
                isCorrect &= divider == s.charAt(i);
            } else {
                isCorrect &= Character.isDigit(s.charAt(i));
            }
        }
        return isCorrect;
    }

    private String concatString(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;
    }

    @Override
    public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {

    }

    @Override
    public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {

    }

    @Override
    public void afterTextChanged(Editable s) {
        card_num = String.valueOf(s);

        Log.i("TAG", "Card Date:" + s);
        Log.i("TAG", "Card Date :" + cardDateEditText.getEditableText());

        if (s == cardno.getEditableText()) {
            if (!isInputCorrect(s, CARD_NUMBER_TOTAL_SYMBOLS, CARD_NUMBER_DIVIDER_MODULO, CARD_NUMBER_DIVIDER)) {
                s.replace(0, s.length(), concatString(getDigitArray(s, CARD_NUMBER_TOTAL_DIGITS), CARD_NUMBER_DIVIDER_POSITION, CARD_NUMBER_DIVIDER));

            }
            // DO STH
        } else if (s == cardDateEditText.getEditableText()) {
            if (!isInputCorrect(s, CARD_DATE_TOTAL_SYMBOLS, CARD_DATE_DIVIDER_MODULO, CARD_DATE_DIVIDER)) {
                s.replace(0, s.length(), concatString(getDigitArray(s, CARD_DATE_TOTAL_DIGITS), CARD_DATE_DIVIDER_POSITION, CARD_DATE_DIVIDER));

            } else if (s == cardCVCEditText.getEditableText()) {
                if (s.length() > CARD_CVC_TOTAL_SYMBOLS) {
                    s.delete(CARD_CVC_TOTAL_SYMBOLS, s.length());

                }

            }


        }
    }
}

person Elackya    schedule 10.12.2018    source источник
comment
см. stackoverflow.com/questions/31201349/   -  person Android Team    schedule 10.12.2018
comment
обратитесь к stackoverflow.com/questions/16889502/   -  person Android Team    schedule 10.12.2018
comment
хорошо, дай мне проверить   -  person Elackya    schedule 10.12.2018
comment
@VineshChauhan: уже погуглил, и я не получил подходящего ответа. Это причина публикации этого вопроса.   -  person Elackya    schedule 10.12.2018
comment
Я предлагаю вам использовать java.time, современный API даты и времени Java, и ThreeTenABP (если это необходимо для вашего уровня API): попробуйте YearMonth.parse(s, DateTimeFormatter.ofPattern("MM/yyyy")) и перехватите DateTimeParseException.   -  person Ole V.V.    schedule 10.12.2018


Ответы (1)


Насколько я понимаю, разделитель даты всегда должен находиться в позиции 2.

private static final int CARD_DATE_DIVIDER_POSITION = CARD_DATE_DIVIDER_MODULO - 1; // means divider position is every 2nd symbol beginning with 0

с приведенным выше объявлением, прежде чем добавлять разделитель даты, я должен проверить этот способ (вы можете изменить свой метод isInputCorrect таким образом):

 private boolean isInputCorrect(Editable s, int size, int dividerPosition, char divider) {
        boolean isCorrect = s.length() <= size;

        for (int i = 0; i < s.length(); i++) {
            if (i > 0 && (i + 1) % dividerPosition == 0) {
                if (divider=='/') {
                    if (i==2) {
                        isCorrect &= divider == s.charAt(i);
                    }
                }

            } else {
                isCorrect &= Character.isDigit(s.charAt(i));

            }
        }
        return isCorrect;
    }

И затем, после того, как текст изменился, его можно немного изменить, чтобы он стал следующим:

@Override
    public void afterTextChanged(Editable s) {
        card_num = String.valueOf(s);
        String ss=cardDateEditText.getText().toString();

        Log.i("TAG", "Card Date:" + s);
        Log.i("TAG", "Card Date :" + ss);

        if (s == cardno.getEditableText()) {
            if (!isInputCorrect(s, CARD_NUMBER_TOTAL_SYMBOLS, CARD_NUMBER_DIVIDER_MODULO, CARD_NUMBER_DIVIDER)) {
                s.replace(0, s.length(), concatString(getDigitArray(s, CARD_NUMBER_TOTAL_DIGITS), CARD_NUMBER_DIVIDER_POSITION, CARD_NUMBER_DIVIDER));

            }
        } else if (s == cardDateEditText.getEditableText()) {
            if (s.length()<=CARD_DATE_TOTAL_SYMBOLS)
            {
                if (!isInputCorrect(s, CARD_DATE_TOTAL_SYMBOLS, CARD_DATE_DIVIDER_MODULO, CARD_DATE_DIVIDER)) {
                    Log.e("TAG",s+"");

                    s.replace(0, s.length(), concatString(getDigitArray(s, CARD_DATE_TOTAL_DIGITS), CARD_DATE_DIVIDER_POSITION, CARD_DATE_DIVIDER));

                }
            }else
            {
                s.delete(CARD_DATE_TOTAL_SYMBOLS,s.length());
            }


        } else if (s == cardCVCEditText.getEditableText()) {
                if (s.length() > CARD_CVC_TOTAL_SYMBOLS) {
                    s.delete(CARD_CVC_TOTAL_SYMBOLS, s.length());

                }

            }


        }

Таким образом, вы также проверяете длину редактируемого текста.

Разделитель даты должен быть включен только один раз и сразу после месяца, представленного двумя первыми символами. Это означает, что последняя цифра должна быть на 2-й позиции индекса 1, в этот момент i==1. Таким образом, никакой другой разделитель не будет добавлен. Мне нужно проверить, установлен ли разделитель для даты, чтобы знать, что я имею дело с датой, а затем проверить, не больше ли индекс или равен 2.

Вот как я мог справиться с этим. Я надеюсь, это поможет.

person Gratien Asimbahwe    schedule 10.12.2018
comment
что я ценю - person Elackya; 10.12.2018
comment
i — индекс цифры в массиве - person Gratien Asimbahwe; 10.12.2018
comment
Я просто использовал его так, как он есть в вашем коде, но я только что проверил, прежде чем добавить разделитель - person Gratien Asimbahwe; 10.12.2018
comment
я должен инициализировать я как 0? И что значит отформатировано? - person Elackya; 10.12.2018
comment
Давайте продолжим обсуждение в чате. - person Elackya; 10.12.2018