EditText上的InputFilter导致重复文本

时间:2013-08-30 09:06:17

标签: android android-edittext android-input-filter

我正在尝试实现一个EditText,它只限制数字[A-Z0-9]的数字输入限制。

我从一些帖子开始使用InputFilter方法。但是这里我在Samsung Galaxy Tab 2上遇到了一个问题,但在模拟器或Nexus 4中没有。

问题是这样的:

  1. 当我输入“A”时,文字显示为“A”,它的好处
  2. 现在当我输入“B”时,文字应该是“AB”,但它给了我“AAB” 这看起来非常奇怪。
  3. 简而言之,它重复了字符

    以下是我正在使用此代码的代码:

    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>
    

    我完全坚持这个,所以任何帮助都会非常感激。

9 个答案:

答案 0 :(得分:10)

字符重复的问题来自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);
}

答案 1 :(得分:2)

我在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中键入任何特殊符号。只允许使用大写字母数字字符。

答案 2 :(得分:1)

可以将

InputFilters附加到可编辑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 "";
        }
    }

答案 3 :(得分:1)

我遇到了同样的问题,在使用此处发布的解决方案修复后,仍然存在自动填充的键盘问题。一种解决方案是将inputType设置为&#39; visiblePassword&#39;但这种减少功能不是吗?

我能够通过在filter()方法中返回非空结果时使用调用来修复解决方案

TextUtils.copySpansFrom((Spanned) source, start, newString.length(), null, newString, 0);

这会将自动完成跨度复制到新结果中,并在选择自动填充建议时修复重复的奇怪行为。

答案 4 :(得分:1)

对我而言,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)
        }
    }
})

效果很好。

答案 5 :(得分:0)

试试这个:

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()方法一次接受多个字符时进行过滤,例如从剪贴板粘贴文本

答案 6 :(得分:0)

以下解决方案还支持自动完成键盘选项

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

答案 7 :(得分:0)

我几次遇到这个问题。 适当地在xml中设置某些类型的inputTypes是问题的根源。 要在InputFilterTextWatcher中解决此问题而无需任何其他逻辑,只需在代码中设置输入类型,而不是像下面这样的xml:

editText.setInputType(getInputType() | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);

答案 8 :(得分:0)

最近我遇到了同样的问题 问题的原因是...如果输入字符串没有变化,则不返回源字符串,返回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;
    }
}

此代码中发生了什么,有一个正则表达式,我们将找到除字母和数字之外的所有字符,现在它将用空字符串替换所有字符,然后剩余的字符串将具有字母和数字。