Как создать для текстового поля маску ввода?
Нужно, чтобы пользователь вводил в текстовое поле цифры даты в формате xx.xx.xxxx (то есть чтобы точки уже стояли и был возможен ввод только цифры). Дополнительно чтобы была проверка на ввод даты - то есть что бы не вводили 32.03.2021, а также если год не високосный, то февраль могли бы ввести только 28.02.2011, а не 29.02.2011 Как это можно сделать? (чтобы не использовать DataPicker)
Ответы (2 шт):
К примеру ваш EditText
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/ac_registration_et_birth_date"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="number"
android:hint="ДД.ММ.ГГГГ" />
Мы можем создать класс DateInputMask, который выполнит нашу задачу
class DateInputMask(private val input: EditText, private val saveDate: (dateTitle: String) -> Unit) : TextWatcher {
private var current = ""
private val ddmmyyyy = "DDMMYYYY"
private val cal: Calendar = Calendar.getInstance()
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
if (s.toString() == current) {
return
}
var clean = s.toString().replace("[^0-9]".toRegex(), "")
val cleanC = current.replace("[^0-9]".toRegex(), "")
val cl = clean.length
var sel = cl
var i = 2
while (i <= cl && i < 6) {
sel++
i += 2
}
//Fix for pressing delete next to a forward slash
if (clean == cleanC) sel--
if (clean.length < 8) {
clean += ddmmyyyy.substring(clean.length)
} else {
//This part makes sure that when we finish entering numbers
//the date is correct, fixing it otherwise
var day = clean.substring(0, 2).toInt()
var mon = clean.substring(2, 4).toInt()
var year = clean.substring(4, 8).toInt()
mon = if (mon < 1) 1 else if (mon > 12) 12 else mon
cal.set(Calendar.MONTH, mon - 1)
year = if (year < 1900) 1900 else if (year > 2020) 2020 else year
cal.set(Calendar.YEAR, year)
day = if (day > cal.getActualMaximum(Calendar.DATE)) cal.getActualMaximum(Calendar.DATE) else day
clean = String.format("%02d%02d%02d", day, mon, year)
}
clean = String.format("%s.%s.%s", clean.substring(0, 2),
clean.substring(2, 4),
clean.substring(4, 8))
sel = if (sel < 0) 0 else sel
current = clean
input.setText(current)
input.setSelection(if (sel < current.length) sel else current.length)
saveDate(if (sel == 10) input.text.toString() else "")
}
override fun afterTextChanged(s: Editable) {}
init {
input.addTextChangedListener(this)
}
}
И осталось нам подключить его к нашему EditText
DateInputMask(ac_registration_et_birth_date) { it ->
//Ваша логика
}
Чтобы проверить корректность введенной пользователем даты, можно написать такую функцию:
fun parseLocalDateOrNull(text: String, formatter: DateTimeFormatter) =
try {
LocalDate.parse(text, formatter)
} catch (ex: DateTimeParseException) {
null
}
Как видно из названия, функция вернет дату либо null, если дата невалидная:
val formatter = DateTimeFormatter.ofPattern("dd.MM.uuuu")
.withResolverStyle(ResolverStyle.STRICT)
val date = parseLocalDateOrNull("31.02.1970", formatter)
if (date == null) {
// введена некорректная дата
}
Класс LocalDate доступен только для Android API 26 и выше. Для старых версий Андроида можно воспользоваться библиотекой Joda-Time.