我想实现这样的算法:
一旦用户开始输入"MM"的数字,它应该在用户输入"MM"的两个数字后给出"/",然后,它应该只允许输入"yy"的最后两位数字。如何实现此类功能?
android:maxLength="5"
并设置为手机以编辑文本,以便它可以显示"/">
android:inputType="phone"
在文本观察者上执行此操作....我将稍后验证正确的 mm/yy 月份年份,以避免用户输入数据,例如 55/66 最大值应该是 12/31,但它应该验证少于或 30 天的月份......
@Override
public void afterTextChanged(Editable editable) {
if (editable.length() > 0 && (editable.length() % 3) == 0) {
final char c = editable.charAt(editable.length() - 1);
if ('/' == c) {
editable.delete(editable.length() - 1, editable.length());
}
}
if (editable.length() > 0 && (editable.length() % 3) == 0) {
char c = editable.charAt(editable.length() - 1);
if (Character.isDigit(c) && TextUtils.split(editable.toString(), String.valueOf("/")).length <= 2) {
editable.insert(editable.length() - 1, String.valueOf("/"));
}
}
}
我只是实现了一种像 Uber 信用卡日期格式这样的方法,具有自动检查、自动完成、自动移动到 CVV 编辑文本的功能。
<EditText
android:id="@+id/credit_card_expire_et"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginRight="@dimen/activity_horizontal_margin"
android:layout_weight="1"
android:hint="MM/YY"
android:inputType="number"
android:maxLength="5"
android:maxLines="1" />
<EditText
android:id="@+id/credit_card_cvv_et"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/activity_horizontal_margin"
android:layout_weight="1"
android:hint="CVV"
android:inputType="number"
android:maxLength="3"
android:maxLines="1" />
.
@BindView(R.id.credit_card_expire_et)
EditText creditExpireEt;
@BindView(R.id.credit_card_cvv_et)
EditText creditCVVEt;
@OnTextChanged(value = R.id.credit_card_expire_et, callback = BEFORE_TEXT_CHANGED)
void beforeExpireEtChanged() {
previousLength = creditExpireEt.getText().toString().length();
}
@OnTextChanged(R.id.credit_card_expire_et)
void autoFixAndMoveToNext() {
int length = creditExpireEt.getText().toString().trim().length();
if (previousLength <= length && length < 3) {
int month = Integer.parseInt(creditExpireEt.getText().toString());
if (length == 1 && month >= 2) {
String autoFixStr = "0" + month + "/";
creditExpireEt.setText(autoFixStr);
creditExpireEt.setSelection(3);
} else if (length == 2 && month <= 12) {
String autoFixStr = creditExpireEt.getText().toString() + "/";
creditExpireEt.setText(autoFixStr);
creditExpireEt.setSelection(3);
} else if (length ==2 && month > 12) {
creditExpireEt.setText("1");
creditExpireEt.setSelection(1);
}
} else if (length == 5) {
creditCVVEt.requestFocus(); // auto move to next edittext
}
}
EditText et_expiry_date= (EditText) findViewById(R.id.et_expiry_date);
et_expiry_date.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
String current = s.toString();
if (current.length() == 2 && start == 1) {
et_expiry_date.setText(current + "/");
et_expiry_date.setSelection(current.length() + 1);
}
else if (current.length() == 2 && before == 1) {
current = current.substring(0, 1);
et_expiry_date.setText(current);
et_expiry_date.setSelection(current.length());
}
}
@Override
public void afterTextChanged(Editable s) {}
});
在 youredittext.addTextChangedListener 上添加这些
内容@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
if (s.length() == 2) {
if(start==2 && before==1 && !s.toString().contains("/")){
youredittext.setText(""+s.toString().charAt(0));
youredittext.setSelection(1);
}
else {
youredittext.setText(s + "/");
youredittext.setSelection(3);
}
}
}
首先将 EditText 的最大字符数设置为 5,如下所示:
android:maxLength="5"
并设置为数字编辑文本
android:inputType="number"
然后将 onEditTextChangedListener 添加到 EditText 中,以检测字符数是否更改为 2 并且没有从 3 更改为 2,如果删除了 "/" 之前的数字,则删除"/":
edit_text.addTextChangedListener(object : TextWatcher {
override fun afterTextChanged(p0: Editable?) {}
override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}
override fun onTextChanged(p0: CharSequence?, start: Int, removed: Int, added: Int) {
if (start == 1 && start+added == 2 && p0?.contains('/') == false) {
edit_text.setText(p0.toString() + "/")
} else if (start == 3 && start-removed == 2 && p0?.contains('/') == true) {
edit_text.setText(p0.toString().replace("/", ""))
}
}
})
private static final String EXP_DATE_REGAX = "(0[1-9]|1[0-2])[0-9]{2}";
if (!edt_expiry_date.getText().toString().isEmpty()) {
Pattern pattern = Pattern.compile(EXP_DATE_REGAX);
Matcher matcher = pattern.matcher(edt_expiry_date.getText().toString());
if(!matcher.find()){
edt_expiry_date.setError("Invalid Expiry Date");
}else{
Calendar c = Calendar.getInstance();
int year = c.get(Calendar.YEAR) % 100;
int month = c.get(Calendar.MONTH)+1;
if(Integer.parseInt((edt_expiry_date.getText().toString().substring(2)))>=year){
if(Integer.parseInt((edt_expiry_date.getText().toString().substring(2)))==year){
if(Integer.parseInt((edt_expiry_date.getText().toString().substring(0,2)))>=month){
str_expiry_date = edt_expiry_date.getText().toString();
dialog.dismiss();
}else{
edt_expiry_date.setError("Invalid Expiry Date");
}
}else{
str_expiry_date = edt_expiry_date.getText().toString();
dialog.dismiss();
}
}else{
edt_expiry_date.setError("Invalid Expiry Date");
}
// dialog.dismiss();
}
} else {
edt_expiry_date.setError("Enter Expiry Date");
}
基于文本的日期条目所需的问题和字符串操作在这里似乎不值得。如果用户返回到字符串的开头并开始键入,会发生什么情况?如果用户开始输入错误的格式,会发生什么情况?您必须考虑大量情况,而没有很好的方法来控制用户可以输入的内容。在这些情况下,我只会使用类似于此解决方案中的日期选取器。
如果您愿意,您可以保留 EditText,只需设置 onClickListener 以在选择时调出日期选择器。不过,我建议在其上设置这两个字段:
android:cursorVisible="false"
android:focusable="false"
这样,编辑文本看起来就不像可以输入了。我唯一的建议或对另一个答案的补充是"清除"按钮,以便在需要时可以擦除 EditText 值。为此,只需通过中性按钮添加它,如下所示:
builder.setView(dialog)
// Add action buttons
.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
listener.onDateSet(null, yearPicker.getValue(), monthPicker.getValue(), 0);
}
})
.setNeutralButton(R.string.clear, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
//check for a month value of -1 in onDateSet to clear current field
listener.onDateSet(null, -1, -1, 0);
}
})
.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
MonthYearPickerFragment.this.getDialog().cancel();
}
});
然后要检查并查看是否应清除该字段,只需执行以下操作:
@Override
public void onDateSet(DatePicker datePicker, int i, int i1, int i2) {
if (i > -1){
et.setText(i1 + "/" + i);
} else {
et.setText("");
}
}
在 Kotlin 中,格式如下
"月/年">
你可以使用它,
et_expire_date.addTextChangedListener(object : TextWatcher {
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
var working = s.toString()
var isValid = true
if (working.length == 2 && before == 0) {
if (Integer.parseInt(working) < 1 || Integer.parseInt(working) > 12) {
isValid = false
} else {
working += "/"
et_expire_date.setText(working)
et_expire_date.setSelection(working.length)
}
} else if (working.length == 5 && before == 0) {
val enteredYear = working.substring(3)
val currentYear = Calendar.getInstance().get(Calendar.YEAR) % 100//getting last 2 digits of current year i.e. 2018 % 100 = 18
if (Integer.parseInt(enteredYear) < currentYear) {
isValid = false
}
} else if (working.length != 5) {
isValid = false
}
if (!isValid) {
et_expire_date.error = getString(R.string.enter_valid_date_mm_yy)
} else {
et_expire_date.error = null
}
}
override fun afterTextChanged(s: Editable) {}
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
})
其中et_expire_date
是用于日期输入的编辑文本
使用 TextWatcher,例如:
EditText editText = (EditText) findViewById(R.id.yourEditTextId);
yourEditText.addTextChangedListener(new TextWatcher() {
public void afterTextChanged(Editable s) {
// Do what you want here
String myStr = s.toString();
// Check if MM and do what you want
}
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
public void onTextChanged(CharSequence s, int start, int before, int count) {}
});
Kotlin 版本的 @Goodlife
override fun afterTextChanged(s: Editable?) {
if (s!!.isNotEmpty() && (s.length % 3) == 0) {
val c = s[s.length-1]
if (c == '/') {
s.delete(s.length-1, s.length)
}
}
if (s.isNotEmpty() && (s.length % 3) == 0) {
val c = s[s.length-1]
if (Character.isDigit(c) && TextUtils.split(s.toString(), "/").size <= 2) {
s.insert(s.length-1, "/")
}
}
}
简单答案,将长度设置为 5 表示 mm/yy,或为 mm/yyyy 设置 7
YourEditText.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
int len=s.toString().length();
if (before == 0 && len == 2)
YourEditText.append("/");
}
@Override
public void afterTextChanged(Editable s) {
}
});