I\'m trying to implement an EditText that limits input to alpha chars only [A-Za-z].
I started with the InputFilter method from this post. When I type \"a%\" the text d
We had a similar problem and I believe a solution[0] that would work for you as well. Our requirements were to implement an EditText that stripped rich text input. For example, if the user copied bold text to their clipboard and pasted it into the EditText, the EditText should remove the bold emphasis styling and preserve only the plain text.
The solution class looks something like this:
public class PlainEditText extends EditText {
public PlainEditText(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
addFilter(this, new PlainTextInputFilter());
}
private void addFilter(TextView textView, InputFilter filter) {
InputFilter[] filters = textView.getFilters();
InputFilter[] newFilters = Arrays.copyOf(filters, filters.length + 1);
newFilters[filters.length] = filter;
textView.setFilters(newFilters);
}
private static class PlainTextInputFilter implements InputFilter {
@Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest,
int dstart, int dend) {
return stripRichText(source, start, end);
}
private CharSequence stripRichText(CharSequence str, int start, int end) {
// ...
}
}
}
Our original implementation for stripRichText() was simple:
// -- BROKEN. DO NOT USE --
String plainText = str.subSequence(start, end).toString();
return plainText;
The Java base String class doesn't retain any styling information so converting the CharSequence interface to a concrete String copies only plain text.
What we didn't realize was that some Android soft keyboards add and depend on temporary compositional hints for typos and other things. The problem manifests by removing the hints as well as repeating characters in an unexpected way (usually doubling the entire EditText field's input). The documentation[1] for InputFilter.filter() communicates the requirement this way:
* Note: If source is an instance of {@link Spanned} or
* {@link Spannable}, the span objects in the source should be
* copied into the filtered result (i.e. the non-null return value).
I believe the proper solution is to preserve temporary spans:
/** Strips all rich text except spans used to provide compositional hints. */
private CharSequence stripRichText(CharSequence str, int start, int end) {
String plainText = str.subSequence(start, end).toString();
SpannableString ret = new SpannableString(plainText);
if (str instanceof Spanned) {
List
[0] Actual implementation available here: https://github.com/wikimedia/apps-android-wikipedia/blob/e9ffffd8854ff15cde791a2e6fb7754a5450d6f7cf/app/src/main/java/org/wikipedia/richtext/RichTextUtil.java
[1] https://android.googlesource.com/platform/frameworks/base/+/029942f77d05ed3d20256403652b220c83dad6e1/core/java/android/text/InputFilter.java#37