EditText
をフォーマットして「dd/mm/yyyy
"は、TextWatcher
を使用して、マスクを使用して「0.05€」のようにユーザー入力をフォーマットするのと同じ方法でフォーマットします。文字の制限については話していません。以前の形式にマスクするだけで、日付を検証します。
プロジェクト用にこれを書いたTextWatcher
、うまくいけば誰かに役立つでしょう。 notはユーザーが入力した日付を検証することに注意してください。ユーザーが日付の入力を完了していない可能性があるため、フォーカスが変更されたときにそれを処理する必要があります。
pdate 25/06最終的なコードが改善されるかどうかを確認するためにwikiにしました。
更新07/06最後に、ウォッチャー自体に何らかの検証を追加しました。無効な日付を使用して以下を実行します。
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());
}
}
他の2つの関数も実装します。
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
@Override
public void afterTextChanged(Editable s) {}
};
これにより、次の効果が得られます。文字を削除または挿入すると、dd/mm/yyyy
マスクが表示または非表示になります。コードをできるだけシンプルにしようとしたため、他のフォーマットマスクに合わせて簡単に変更できるはずです。
現在の答えは非常によく、私自身の解決策に私を導くのに役立ちました。この質問にはすでに有効な答えがありますが、自分のソリューションを投稿することにした理由はいくつかあります。
それを使用するには、次のようにします。
そして、解決策を以下に示します。
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) {}
}
}
juanCortésのコードをよりクリーンに使用する方法をクラスに入れます:
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);
追加 Android:inputType="date"
をEditText
に
検証なしのKotlinバージョン
editText.addTextChangedListener(object : TextWatcher{
var sb : StringBuilder = StringBuilder("")
var _ignore = false
override fun afterTextChanged(s: Editable?) {}
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
if(_ignore){
_ignore = false
return
}
sb.clear()
sb.append(if(s!!.length > 10){ s.subSequence(0,10) }else{ s })
if(sb.lastIndex == 2){
if(sb[2] != '/'){
sb.insert(2,"/")
}
} else if(sb.lastIndex == 5){
if(sb[5] != '/'){
sb.insert(5,"/")
}
}
_ignore = true
editText.setText(sb.toString())
editText.setSelection(sb.length)
}
})
JuanCortésのwikiは魅力のように機能します https://stackoverflow.com/a/16889503/348074
ここに私のKotlinバージョン
fun setBirthdayEditText() {
birthdayEditText.addTextChangedListener(object : TextWatcher {
private var current = ""
private val ddmmyyyy = "DDMMYYYY"
private val cal = Calendar.getInstance()
override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
if (p0.toString() != current) {
var clean = p0.toString().replace("[^\\d.]|\\.".toRegex(), "")
val cleanC = current.replace("[^\\d.]|\\.", "")
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 = 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 = Integer.parseInt(clean.substring(0, 2))
var mon = Integer.parseInt(clean.substring(2, 4))
var year = Integer.parseInt(clean.substring(4, 8))
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 > 2100) 2100 else 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 = 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
birthdayEditText.setText(current)
birthdayEditText.setSelection(if (sel < current.count()) sel else current.count())
}
}
override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
}
override fun afterTextChanged(p0: Editable) {
}
})
}
マスキングはすぐに使用できないため、この問題を解決するライブラリを使用してみてください。多くのコーナーケース(既にマスクされているテキストの途中で文字を追加/削除するなど)があり、これを適切に処理するには、多くのコード(およびバグ)が発生します。
利用可能なライブラリは次のとおりです。
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
**これらのライブラリを書いている時点では問題がないわけではないので、自分に最も適したライブラリを選択してコードをテストするのはあなたの責任です。
この回答では、残りの型指定されていない数字に完全なマスクは適用されません。しかし、それは関連しており、私が必要とした解決策です。 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;
}
}
_