如何屏蔽EditText以显示dd / mm / yyyydate格式

我如何格式化EditText以遵循“ dd/mm/yyyy ”格式,就像我们可以使用TextWatcher屏蔽用户input看起来像“0.05€”一样。 我不是在谈论限制字符,或者validationdate,只是掩饰到以前的格式。

Solutions Collecting From Web of "如何屏蔽EditText以显示dd / mm / yyyydate格式"

我为这个项目编写了这个TextWatcher ,希望对某个人有帮助。 请注意,它不会validation用户input的date,并且您应该在焦点更改时处理该问题,因为用户可能尚未inputdate。

更新25/06把它作为一个维基,看看我们是否达到了更好的最终代码。

更新07/06我最后添加了一些validation的观察者本身。 它将使用无效date执行以下操作:

  • 如果月份大于12,则为12(12月)
  • 如果date大于所选月份的date,则将其设置为当月的最大值。
  • 如果年份不在1900-2100的范围内,请将其更改为范围内

这个validation符合我的需求,但是你们中的一些可能想要稍微改变它,范围很容易改变,你可以将这个validation挂钩到Toast消息,例如通知用户我们已经修改了他/她的date无效。

在这段代码中,我将假设我们有一个引用了我们的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 eg 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()); } } 

我们也执行其他两个function,因为我们必须

  @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) {} @Override public void afterTextChanged(Editable s) {} }; 

这会产生以下效果,删除或插入字符将显示或隐藏dd/mm/yyyy掩码。 应该很容易修改,以适应其他格式掩码,因为我试图离开代码尽可能简单。

在这里输入图像说明

目前的答案是非常好的,并帮助指导我自己的解决scheme。 有几个原因,我决定发布我自己的解决scheme,即使这个问题已经有一个有效的答案:

  • 我在Kotlin工作,而不是Java。 发现自己有同样问题的人将不得不翻译当前的解决scheme。
  • 我想写一个更清晰的答案,让人们更容易适应自己的问题。
  • 正如dengue8830所build议的那样,我在一个类中封装了这个问题的解决scheme,所以任何人都可以使用,而不用担心实现。

要使用它,只需要做一些事情:

  • DateInputMask(mEditText)。听()

解决scheme如下所示:

 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) {} } } 

一个更清晰的方式来使用胡安科尔特斯的代码被放在一个类:

 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 eg 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); 

这个答案不适用于其余的非types数字的完整掩码。 但是,这是相关的,是我需要的解决scheme。 它的工作方式类似于PhoneNumberFormattingTextWatcher工作方式。

当你input的时候,添加斜杠来分隔date格式,如mm/dd/yyyy它不做任何validation – 只是格式。

不需要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; } }