InputFilter on EditText cause repeating text

sam_k picture sam_k · Aug 30, 2013 · Viewed 13.6k times · Source

I'm trying to implement an EditText that limits input to Capital chars only [A-Z0-9] with digits as well.

I started with the InputFilter method from some post.But here I am getting one problem on Samsung Galaxy Tab 2 but not in emulator or Nexus 4.

Problem is like this :

  1. When I type "A" the text shows as "A" its good
  2. Now when I type "B" so text should be "AB" but it gives me "AAB" this looks very Strange.

In short it repeats chars

Here's the code I'm working with this code :

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 file code :

<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>

I'm totally stuck up on this one, so any help here would be greatly appreciated.

Answer

Kamil Seweryn picture Kamil Seweryn · Dec 2, 2013

The problem of characters duplication comes from InputFilter bad implementation. Rather return null if replacement should not change:

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