Как замаскировать EditText для отображения формата даты dd/mm/yyyy
как я могу отформатировать EditText
следовать "dd/mm/yyyy
" форматировать так же, как мы можем форматировать с помощью TextWatcher
to маска пользовательский ввод выглядит как " 0.05€". Я не говорю об ограничении символов или проверке даты, просто маскируя предыдущий формат.
5 ответов
я написал TextWatcher
для проекта, надеюсь это будет полезно кому-то. Обратите внимание, что это делает не проверьте дату, введенную пользователем, и вы должны обработать это при изменении фокуса, так как пользователь, возможно, не закончил ввод даты.
обновление 25/06 сделал его wiki, чтобы увидеть, если мы достигнем лучшего окончательного кода.
07/06 обновление В конце концов я добавил что-то вроде подтверждения самому наблюдателю. Он будет делать следующее с недопустимыми датами:
- если месяц больше 12, это будет 12 (декабрь)
- если дата больше, чем для выбранного месяца, сделайте ее максимальной для этого месяца.
- если год не находится в диапазоне
1900-2100
, изменить его, чтобы быть в диапазоне
эта проверка соответствует моим потребностям, но некоторые из вас могут захотеть немного изменить ее, диапазоны легко меняются, и вы можете подключить это проверок Toast
сообщение например, чтобы уведомить Пользователя о том, что мы изменили его/ее дату, поскольку это был инвалид.
в этом коде, я предполагаю, что у нас есть ссылка на наш EditText
под названием date
что это TextWatcher
прикрепленный к нему, это можно сделать что-то вроде этого:
EditText date;
date = (EditText)findViewById(R.id.whichdate);
date.addTextChangedListener(tw);
TextWatcher tw = new TextWatcher() {
private String current = "";
private String ddmmyyyy = "DDMMYYYY";
private Calendar cal = Calendar.getInstance();
когда пользователь изменяет текст EditText
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
if (!s.toString().equals(current)) {
String clean = s.toString().replaceAll("[^\d.]|\.", "");
String cleanC = current.replaceAll("[^\d.]|\.", "");
int cl = clean.length();
int sel = cl;
for (int i = 2; i <= cl && i < 6; i += 2) {
sel++;
}
//Fix for pressing delete next to a forward slash
if (clean.equals(cleanC)) sel--;
if (clean.length() < 8){
clean = clean + ddmmyyyy.substring(clean.length());
}else{
//This part makes sure that when we finish entering numbers
//the date is correct, fixing it otherwise
int day = Integer.parseInt(clean.substring(0,2));
int mon = Integer.parseInt(clean.substring(2,4));
int year = Integer.parseInt(clean.substring(4,8));
mon = mon < 1 ? 1 : mon > 12 ? 12 : mon;
cal.set(Calendar.MONTH, mon-1);
year = (year<1900)?1900:(year>2100)?2100:year;
cal.set(Calendar.YEAR, year);
// ^ first set year for the line below to work correctly
//with leap years - otherwise, date e.g. 29/02/2012
//would be automatically corrected to 28/02/2012
day = (day > cal.getActualMaximum(Calendar.DATE))? cal.getActualMaximum(Calendar.DATE):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 = sel < 0 ? 0 : sel;
current = clean;
date.setText(current);
date.setSelection(sel < current.length() ? sel : current.length());
}
}
мы также реализуем другие две функции, потому что у нас есть к
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
@Override
public void afterTextChanged(Editable s) {}
};
это производит следующий эффект, где удаление или вставка символов покажет или скроет dd/mm/yyyy
маска. Это должно быть легко изменить, чтобы соответствовать другим маскам формата, так как я пытался оставить код как можно проще.
более чистый способ использовать код Хуана Кортеса помещается в класс:
public class DateInputMask implements TextWatcher {
private String current = "";
private String ddmmyyyy = "DDMMYYYY";
private Calendar cal = Calendar.getInstance();
private EditText input;
public DateInputMask(EditText input) {
this.input = input;
this.input.addTextChangedListener(this);
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
if (s.toString().equals(current)) {
return;
}
String clean = s.toString().replaceAll("[^\d.]|\.", "");
String cleanC = current.replaceAll("[^\d.]|\.", "");
int cl = clean.length();
int sel = cl;
for (int i = 2; i <= cl && i < 6; i += 2) {
sel++;
}
//Fix for pressing delete next to a forward slash
if (clean.equals(cleanC)) sel--;
if (clean.length() < 8){
clean = clean + ddmmyyyy.substring(clean.length());
}else{
//This part makes sure that when we finish entering numbers
//the date is correct, fixing it otherwise
int day = Integer.parseInt(clean.substring(0,2));
int mon = Integer.parseInt(clean.substring(2,4));
int year = Integer.parseInt(clean.substring(4,8));
mon = mon < 1 ? 1 : mon > 12 ? 12 : mon;
cal.set(Calendar.MONTH, mon-1);
year = (year<1900)?1900:(year>2100)?2100:year;
cal.set(Calendar.YEAR, year);
// ^ first set year for the line below to work correctly
//with leap years - otherwise, date e.g. 29/02/2012
//would be automatically corrected to 28/02/2012
day = (day > cal.getActualMaximum(Calendar.DATE))? cal.getActualMaximum(Calendar.DATE):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 = sel < 0 ? 0 : sel;
current = clean;
input.setText(current);
input.setSelection(sel < current.length() ? sel : current.length());
}
@Override
public void afterTextChanged(Editable s) {
}
}
тогда вы можете использовать его
new DateInputMask(myEditTextInstance);
текущий ответ очень хорош и помог направить меня к моему собственному решению. Есть несколько причин, почему я решил опубликовать свое собственное решение, хотя на этот вопрос уже есть действительный ответ:
- Я работаю в Котлине, а не на Java. Люди, которые оказываются с той же проблемой, должны будут перевести текущее решение.
- Я хотел написать ответ, который был более разборчивым, чтобы люди могли легче адаптировать его к своим собственным проблемы.
- как предложил dengue8830, я инкапсулировал решение этой проблемы в класс, поэтому любой может использовать, даже не беспокоясь о реализации.
чтобы использовать его, просто сделайте что-то вроде:
- DateInputMask (mEditText).слушайте ()
и решение показано ниже:
class DateInputMask(val input : EditText) {
fun listen() {
input.addTextChangedListener(mDateEntryWatcher)
}
private val mDateEntryWatcher = object : TextWatcher {
var edited = false
val dividerCharacter = "/"
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
if (edited) {
edited = false
return
}
var working = getEditText()
working = manageDateDivider(working, 2, start, before)
working = manageDateDivider(working, 5, start, before)
edited = true
input.setText(working)
input.setSelection(input.text.length)
}
private fun manageDateDivider(working: String, position : Int, start: Int, before: Int) : String{
if (working.length == position) {
return if (before <= position && start < position)
working + dividerCharacter
else
working.dropLast(1)
}
return working
}
private fun getEditText() : String {
return if (input.text.length >= 10)
input.text.toString().substring(0,10)
else
input.text.toString()
}
override fun afterTextChanged(s: Editable) {}
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
}
}
этот ответ не применяет полную маску для оставшихся нетипизированных цифр. Тем не менее, это связано и является решением, которое мне нужно. Он работает аналогично how PhoneNumberFormattingTextWatcher
строительство.
при вводе он добавляет косые черты для разделения даты в формате mm/dd/yyyy
. это не делает никакой проверки - просто форматирование.
не нужны EditText
ссылка.
Просто установите слушателя, и он работает.
myEditText.addTextChangedListener(new DateTextWatcher());
import android.text.Editable;
import android.text.TextWatcher;
import java.util.Locale;
/**
* Adds slashes to a date so that it matches mm/dd/yyyy.
*
* Created by Mark Miller on 12/4/17.
*/
public class DateTextWatcher implements TextWatcher {
public static final int MAX_FORMAT_LENGTH = 8;
public static final int MIN_FORMAT_LENGTH = 3;
private String updatedText;
private boolean editing;
@Override
public void beforeTextChanged(CharSequence charSequence, int start, int before, int count) {
}
@Override
public void onTextChanged(CharSequence text, int start, int before, int count) {
if (text.toString().equals(updatedText) || editing) return;
String digitsOnly = text.toString().replaceAll("\D", "");
int digitLen = digitsOnly.length();
if (digitLen < MIN_FORMAT_LENGTH || digitLen > MAX_FORMAT_LENGTH) {
updatedText = digitsOnly;
return;
}
if (digitLen <= 4) {
String month = digitsOnly.substring(0, 2);
String day = digitsOnly.substring(2);
updatedText = String.format(Locale.US, "%s/%s", month, day);
}
else {
String month = digitsOnly.substring(0, 2);
String day = digitsOnly.substring(2, 4);
String year = digitsOnly.substring(4);
updatedText = String.format(Locale.US, "%s/%s/%s", month, day, year);
}
}
@Override
public void afterTextChanged(Editable editable) {
if (editing) return;
editing = true;
editable.clear();
editable.insert(0, updatedText);
editing = false;
}
}
попробуйте использовать библиотеку, которая решает эту проблему, так как маскировка недоступна из коробки. Есть много угловых случаев (например, добавление/удаление символов в середине уже замаскированного текста), и для правильной обработки этого вы получите много кода (и ошибок).
вот некоторые доступные библиотеки:
https://github.com/egslava/edittext-mask
https://github.com/dimitar-zabaznoski/MaskedEditText
https://github.com/pinball83/Masked-Edittext
https://github.com/RedMadRobot/input-mask-android
https://github.com/santalu/mask-edittext
** помнить, что на момент написания этих библиотек не без проблем, так что это ваша ответственность, чтобы выбрать какой подходит вам лучше всего и проверить код.