Uche Dim, .
, :
- "13", "1".
- when the user starts to enter the year, after deleting the slash, a slash will be added to save the MM / yy format.
In general, it is almost like the expiration field of new cards in the Play Store.
I created a Kotlin class, but use for Java is also added.
CardExpiryTextWatcher Class:
class CardExpiryTextWatcher(private val mTextInputLayout: TextInputLayout,
private val mServerDate: Date,
private val mListener: DateListener) : TextWatcher {
private val mExpiryDateFormat = SimpleDateFormat("MM/yy", Locale.US)
private var mLastInput = ""
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
}
@SuppressLint("SetTextI18n")
override fun afterTextChanged(s: Editable) {
val input = s.toString()
when (s.length) {
1 -> handleMonthInputForFirstCharacter(input)
2 -> handleMonthInputForSecondCharacter(input)
3 -> addSlashIfNotAddedAtEnd(input)
5 -> validateDateAndCallListener(input)
}
mLastInput = mTextInputLayout.editText!!.text.toString()
}
private fun validateDateAndCallListener(input: String) {
try {
if (input[2] == '/') {
val date = mExpiryDateFormat.parse(input)
validateCardIsNotExpired(date)
}
} catch (e: ParseException) {
mTextInputLayout.error = mTextInputLayout.context.getString(R.string.card_exp_date_error)
}
}
private fun validateCardIsNotExpired(cardExpiry: Date) {
if (DateUtils.isDateBefore(cardExpiry, mServerDate)) {
mTextInputLayout.error = mTextInputLayout.context.getString(R.string.card_expired)
return
}
mListener.onExpiryEntered(cardExpiry)
}
@SuppressLint("SetTextI18n")
private fun addSlashIfNotAddedAtEnd(input: String) {
val lastCharacter = input[input.length - 1]
if (lastCharacter != '/') {
val month = input.substring(0, 2)
mTextInputLayout.editText!!.setText("$month/$lastCharacter")
mTextInputLayout.editText!!.setSelection(mTextInputLayout.editText!!.text.toString().length)
}
}
@SuppressLint("SetTextI18n")
private fun handleMonthInputForSecondCharacter(input: String) {
if (mLastInput.endsWith("/")) {
return
}
val month = Integer.parseInt(input)
if (month > 12) {
mTextInputLayout.editText!!.setText(mLastInput)
mTextInputLayout.editText!!.setSelection(mTextInputLayout.editText!!.text.toString().length)
mTextInputLayout.error = mTextInputLayout.context.getString(R.string.card_exp_date_error)
} else {
mTextInputLayout.editText!!.setText("${mTextInputLayout.editText!!.text}/")
mTextInputLayout.editText!!.setSelection(mTextInputLayout.editText!!.text.toString().length)
}
}
@SuppressLint("SetTextI18n")
private fun handleMonthInputForFirstCharacter(input: String) {
val month = Integer.parseInt(input)
if (month in 2..11) {
mTextInputLayout.editText!!.setText("0${mTextInputLayout.editText!!.text}/")
mTextInputLayout.editText!!.setSelection(mTextInputLayout.editText!!.text.toString().length)
}
}
interface DateListener {
fun onExpiryEntered(date: Date)
}
companion object {
@JvmStatic
fun attachTo(textInputLayout: TextInputLayout, serverDate: Date, listener: DateListener) {
textInputLayout.editText!!.addTextChangedListener(
CardExpiryTextWatcher(textInputLayout, serverDate, listener))
}
}
}
Usage (Kotlin):
CardExpiryTextWatcher.attachTo(inputCardExpiry, mServerDate, object : CardExpiryTextWatcher.DateListener {
override fun onExpiryEntered(date: Date) {
}
})
Usage (Java):
CardExpiryTextWatcher.attachTo(inputCardExpiry, mServerDate, new CardExpiryTextWatcher.DateListener() {
@Override
public void onExpiryEntered(@NonNull Date date) {
}
});
Note: inputCardExpiry is the InputTextLayoutone that contains the EditText.
source
share