我正在尝试实现一个EditText
,它只限制数字[A-Z0-9]的数字输入。
我从一些帖子开始使用InputFilter方法。但是我在三星Galaxy Tab 2上遇到了一个问题,但在模拟器或Nexus 4中却没有。
问题是这样的:
简而言之,它重复着色
这是我正在使用此代码的代码:
public class DemoFilter implements InputFilter {
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart,
int dend) {
if (source.equals("")) { // for backspace
return source;
}
if (source.toString().matches("[a-zA-Z0-9 ]*")) // put your constraints
// here
{
return source.toString().toUpperCase();
}
return "";
}
}
XML文件代码:
<EditText
android:id="@+id/et_licence_plate_1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="3"
android:hint="0"
android:imeOptions="actionNext"
android:inputType="textNoSuggestions"
android:maxLength="3"
android:singleLine="true"
android:textSize="18px" >
</EditText>
我完全坚持这个,所以在这里任何帮助将不胜感激。
字符重复的问题来自InputFilter错误的实现。如果替换不应更改,则返回null:
@Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
boolean keepOriginal = true;
StringBuilder sb = new StringBuilder(end - start);
for (int i = start; i < end; i++) {
char c = source.charAt(i);
if (isCharAllowed(c)) // put your condition here
sb.append(c);
else
keepOriginal = false;
}
if (keepOriginal)
return null;
else {
if (source instanceof Spanned) {
SpannableString sp = new SpannableString(sb);
TextUtils.copySpansFrom((Spanned) source, start, end, null, sp, 0);
return sp;
} else {
return sb;
}
}
}
private boolean isCharAllowed(char c) {
return Character.isUpperCase(c) || Character.isDigit(c);
}
我在Android的InputFilter中发现了很多错误,我不确定这些错误是不是也可能是错误的。但绝对不符合我的要求。所以我选择使用TextWatcher而不是InputFilter
private String newStr = "";
myEditText.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
// Do nothing
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
String str = s.toString();
if (str.isEmpty()) {
myEditText.append(newStr);
newStr = "";
} else if (!str.equals(newStr)) {
// Replace the regex as per requirement
newStr = str.replaceAll("[^A-Z0-9]", "");
myEditText.setText("");
}
}
@Override
public void afterTextChanged(Editable s) {
// Do nothing
}
});
上面的代码不允许用户在EditText中键入任何特殊符号。仅允许使用大写字母数字字符。
InputFilters可以附加到Editable S以限制可以对它们进行的更改。请参阅它强调所做的更改而不是它包含的整个文本。
按照下面提到的......
public class DemoFilter implements InputFilter {
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart,
int dend) {
if (source.equals("")) { // for backspace
return source;
}
if (source.toString().matches("[a-zA-Z0-9 ]*")) // put your constraints
// here
{
char[] ch = new char[end - start];
TextUtils.getChars(source, start, end, ch, 0);
// make the characters uppercase
String retChar = new String(ch).toUpperCase();
return retChar;
}
return "";
}
}
我遇到了同样的问题,在用这里发布的解决方案修复后,仍然存在自动完成键盘的问题。一种解决方案是将inputType设置为'visiblePassword'但是减少功能不是吗?
我能够修复解决方案,当在filter()
方法中返回非null结果时,使用调用
TextUtils.copySpansFrom((Spanned) source, start, newString.length(), null, newString, 0);
这会将自动完成跨度复制到新结果中,并在选择自动完成建议时修复重复的奇怪行为。
同样对我来说,InputFilter
复制了角色。这是我用过的:
Kotlin
版本:
private fun replaceInvalidCharacters(value: String) = value.replace("[a-zA-Z0-9 ]*".toRegex(), "")
textView.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
override fun afterTextChanged(s: Editable) {}
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
val newValue = replaceInvalidCharacters(s.toString())
if (newValue != s.toString()) {
textView.setText(newValue)
textView.setSelection(textView.text.length)
}
}
})
效果很好。
试试这个:
class CustomInputFilter implements InputFilter {
StringBuilder sb = new StringBuilder();
@Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
Log.d(TAG, "filter " + source + " " + start + " " + end + " dest " + dest + " " + dstart + " " + dend);
sb.setLength(0);
for (int i = start; i < end; i++) {
char c = source.charAt(i);
if (Character.isUpperCase(c) || Character.isDigit(c) || c == ' ') {
sb.append(c);
} else
if (Character.isLowerCase(c)) {
sb.append(Character.toUpperCase(c));
}
}
return sb;
}
}
这也允许在filter()方法一次接受多个字符时进行过滤,例如从剪贴板粘贴的文本
以下解决方案还支持自动完成键盘选项
editTextFreeNote.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 newStr = s.toString();
newStr = newStr.replaceAll( "[a-zA-Z0-9 ]*", "" );
if(!s.toString().equals( newStr )) {
editTextFreeNote.setText( newStr );
editTextFreeNote.setSelection(editTextFreeNote.getText().length());
}
}
@Override
public void afterTextChanged(Editable s) {}
} );
我以前几次遇到过这个问题。在xml中设置某些类型的inputTypes可能是问题的根源。要在InputFilter
或TextWatcher
中没有任何额外的逻辑来解决它,只需在代码中设置输入类型而不是像这样的xml:
editText.setInputType(getInputType() | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
最近我面临同样问题的原因是...如果输入字符串中没有变化,那么不返回源字符串返回null,某些设备无法正确处理这就是字符正在重复的原因。
在您的代码中,您将返回
return source.toString().toUpperCase();
不要返回这个,return null;
代替return source.toString().toUpperCase();
,但它将是一个补丁修复,它不会处理所有场景,因为所有场景都可以使用此代码。
public class SpecialCharacterInputFilter implements InputFilter {
private static final String PATTERN = "[^A-Za-z0-9]";
// if you want to allow space use this pattern
//private static final String PATTERN = "[^A-Za-z\\s]";
@Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
// Only keep characters that are letters and digits
String str = source.toString();
str = str.replaceAll(PATTERN, AppConstants.EMPTY_STRING);
return str.length() == source.length() ? null : str;
}
}
在这段代码中发生了什么,有一个正则表达式,我们将找到除字母和数字之外的所有字符,现在它将用空字符串替换所有字符,然后剩下的字符串将具有字母和数字。