如何在Android中使用InputFilter限制EditText中的字符数?

194

我希望限制字符仅为0-9、小写字母a-z、大写字母A-Z和空格键。通过设置inputtype,我可以将其限制为数字,但是我无法通过查看文档找出使用Inputfilter的方法。

20个回答

195

我在另一个论坛上发现了这个方法。非常好用。

InputFilter filter = new InputFilter() {
    public CharSequence filter(CharSequence source, int start, int end,
            Spanned dest, int dstart, int dend) {
        for (int i = start; i < end; i++) {
            if (!Character.isLetterOrDigit(source.charAt(i))) {
                return "";
            }
        }
        return null;
    }
};
edit.setFilters(new InputFilter[] { filter });

69
在较新的Android系统(如4.0+),实际上它不起作用了。它们在键盘上方引入了字典建议功能。当您输入一个常用词(比如"the"),后面跟一个不合法的字符(比如"-"),整个单词都会被删除。然后您输入另一个字符(即使是允许的字符,比如"blah"),过滤器也会返回"",并且字段中不显示任何字符。这是因为方法的源参数中包含了"the-blah"的SpannableStringBuilder,并且开始/结束参数跨越整个输入字符串...请查看我的答案以获得更好的解决方案。 - Łukasz Sromek
4
在这个例子中,当它返回“”时,我认为它应该返回应该显示的文本。也就是说,您应该删除非法字符并返回您想要显示的字符串。http://developer.android.com/reference/android/widget/TextView.html#onKeyUp(int, android.view.KeyEvent) - Andrew Mackenzie
如果输入的字符(例如逗号-',')是非法的,而我想将其删除,如何修改上述代码? - twlkyao
!Character.isLetterOrDigit(source.charAt(i)) && !Character.isSpaceChar(source.charAt(i)),以允许空格。 - Leon
@ŁukaszSromek 在新的安卓系统中,尤其是三星设备上,你可以在xml文件中加入一行代码来禁用文本自动完成(如果适合你的需求)。你可以尝试使用android:inputType="textVisiblePassword"来禁用真正的问题——自动完成。虽然这不是正确的方法,但它确实有效。干杯! - Martino Lessio

149

InputFilter在显示字典建议的Android版本中有点复杂。在source参数中,有时会得到一个SpannableStringBuilder,有时会得到一个普通的String

下面的InputFilter应该可以工作。请随意改进这段代码!

new InputFilter() {
    @Override
    public CharSequence filter(CharSequence source, int start, int end,
            Spanned dest, int dstart, int dend) {

        if (source instanceof SpannableStringBuilder) {
            SpannableStringBuilder sourceAsSpannableBuilder = (SpannableStringBuilder)source;
            for (int i = end - 1; i >= start; i--) { 
                char currentChar = source.charAt(i);
                 if (!Character.isLetterOrDigit(currentChar) && !Character.isSpaceChar(currentChar)) {    
                     sourceAsSpannableBuilder.delete(i, i+1);
                 }     
            }
            return source;
        } else {
            StringBuilder filteredStringBuilder = new StringBuilder();
            for (int i = start; i < end; i++) { 
                char currentChar = source.charAt(i);
                if (Character.isLetterOrDigit(currentChar) || Character.isSpaceChar(currentChar)) {    
                    filteredStringBuilder.append(currentChar);
                }     
            }
            return filteredStringBuilder.toString();
        }
    }
}

2
你不想对源进行子序列操作的原因是什么?你认为只执行以下操作是否有问题(以仅允许字母数字和一些特殊字符为例): String replacement = source.subSequence(start, end).toString(); return replacement.replaceAll("[^A-Za-z0-9_\\-@]", ""); - Splash
3
如果重复的词典建议文本出现,这种方法就不适用了。@serwus 在他们的答案中指出了这一点。基本上,如果两种情况下都没有进行修改,你应该返回 null。 - hooby3dfx
3
这段代码完全符合lukasz在之前的回答中所说的,但我遇到了一些非字典单词的问题。当我输入"chiru"时,它会显示三次,像这样:"chiruchiruchiru"。如何解决?它还会接受空格,但如何限制连续的空格? - chiru
3
由于某些原因,当 source instanceof SpannableStringBuilder 时,输入“_AB_”会得到“_AAB_”,就像尝试上一个答案一样。幸运的是,我能够通过使用下面@florian的解决方案来解决这个问题。 - Guillaume
1
@hooby3dfx 绝对是正确的。虽然它最终能够正确获取字符串,但在使用字典/单词自动完成时会出现问题。 - Aravind
显示剩余4条评论

109

更加容易:

<EditText
    android:inputType="text"
    android:digits="0,1,2,3,4,5,6,7,8,9,*,qwertzuiopasdfghjklyxcvbnm" />

9
尽管这似乎是一个完美的答案,但根据文档存在一个问题:“就像所有KeyListener的实现一样,此类仅与硬件键盘有关。软件输入法没有义务触发此类中的方法。”我认为InputFilter可能是更好的选择,尽管更加复杂。 - Craig B
23
很棒的解决方案,只想补充一点:你不需要在中间加上","。你可以使用类似于这样的字符串:"0123456789qwertzuiopasdfghjklyxcvbnmQWERTZUIOPASDFGHJKLYXCVBNM"。 - DeltaCap019
32
不是一种多语言解决方案。 - AAverin
如果您计划在应用程序中使用翻译,请不要使用此解决方案! - grantespo
似乎这个在使用 imeOptions="actionNext" 时可能无法正常工作。 - Pete Doyle
@grantespo,如果我们想输入英文字母和数字,这与翻译有什么关系? - CoolMind

77

所有发布的答案对我都没有用,我自己想出了解决办法:

InputFilter filter = new InputFilter() {
    @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, sb.length(), null, sp, 0);
                return sp;
            } else {
                return sb;
            }           
        }
    }

    private boolean isCharAllowed(char c) {
        return Character.isLetterOrDigit(c) || Character.isSpaceChar(c);
    }
}
editText.setFilters(new InputFilter[] { filter });

3
这是唯一一个正确处理防止字典建议中重复文本的答案!点赞! - hooby3dfx
5
EditText 已经可以拥有自己的过滤器,例如长度过滤器。因此,您最好不要仅仅覆盖这些过滤器,而是希望将您的过滤器添加到已有的过滤器中。 - Aleks N.
我该如何设置最大长度? - XxGoliathusxX
2
这个答案(或者说是 Android 的输入机制)存在一个小问题,就是退格键有时候会让用户感觉不起作用,因为他们在回退已经输入的无效字符,但这些字符仍存留在源缓冲区中。 - jk7
1
与Łukasz Sromek的解决方案相同的问题:空格后面的无效字符将被替换为一个空格。 - Ingo Schalk-Schupp
显示剩余3条评论

30

使用此方法,它可以完美地满足您的需求,并且非常简单。

<EditText
android:inputType="textFilter"
android:digits="@string/myAlphaNumeric" />
在 strings.xml 文件中。
<string name="myAlphaNumeric">abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789</string>

1
我相信你在这里漏掉了空格,但是当然你只需要在“myAlphaNumeric”中添加一个空格就可以让它工作。 - Kraigolas

18

为避免输入类型中的特殊字符

public static InputFilter filter = new InputFilter() {
    @Override
    public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
        String blockCharacterSet = "~#^|$%*!@/()-'\":;,?{}=!$^';,?×÷<>{}€£¥₩%~`¤♡♥_|《》¡¿°•○●□■◇◆♧♣▲▼▶◀↑↓←→☆★▪:-);-):-D:-(:'(:O 1234567890";
        if (source != null && blockCharacterSet.contains(("" + source))) {
            return "";
        }
        return null;
    }
};

您可以像下面这样为编辑文本设置过滤器

edtText.setFilters(new InputFilter[] { filter });

2
不阻止任何这些字符。㋡ ㋛ ☺ ☹ ☻ 〠 シ ッ ツ ヅ Ü 〲 〴 ϡ ﭢ ت ⍡ ⍢ ⍣ ⍤ ⍥ ⍨ ⍩ ὃ ὕ ὣ Ѷ - Anarchofascist

17

我已经做了类似这样的事情,以保持简单:

edit_text.filters = arrayOf(object : InputFilter {
    override fun filter(
        source: CharSequence?,
        start: Int,
        end: Int,
        dest: Spanned?,
        dstart: Int,
        dend: Int
    ): CharSequence? {
        return source?.subSequence(start, end)
            ?.replace(Regex("[^A-Za-z0-9 ]"), "")
    }
})

我们通过将源字符串新部分中的所有不需要的字符替换为空字符串的方式来进行操作。

edit_text变量是我们正在引用的EditText对象。

该代码使用kotlin编写。


1
谢谢!这个解决方案在输入和粘贴文本时表现良好。 - CoolMind
这应该是被接受的答案!除非按照此处所示进行以下检查,否则执行TextWatcher将会导致StackOverFlowError:https://link.medium.com/YfjQwprHUhb - mochadwi
惊人的解决方案。特别是在将拨号器中的数字粘贴到EditText时效果非常好。 - Satyam Gondhale
请注意,InputFilter 可能与 TextWatcher 不兼容。如果它不能按预期工作(清除文本),请检查您是否添加了 TextWatcherInputFilter 将重置 maxLength。要启用它,请使用 edit_text.filters = arrayOf(*aboveInputFilter*, InputFilter.LengthFilter(10)) - CoolMind

8

首先在 strings.xml 文件中添加:

<string name="vin_code_mask">0123456789abcdefghjklmnprstuvwxyz</string>

XML:

android:digits="@string/vin_code_mask"

使用Kotlin编写的代码:

edit_text.filters += InputFilter { source, start, end, _, _, _ ->
    val mask = getString(R.string.vin_code_mask)
    for (i in start until end) {
        if (!mask.contains(source[i])) {
            return@InputFilter ""
        }
    }
    null
}

奇怪的是,在模拟器的软键盘上运行起来很奇怪。

警告! 下面的代码将过滤所有字母和其他符号,只保留数字键盘用于软件键盘。仅支持数字键盘在智能手机上出现。

edit_text.keyListener = DigitsKeyListener.getInstance(context.getString(R.string.vin_code_mask))

我通常也会设置maxLengthfiltersinputType


7

没错,最好的方法是在XML布局中使用以下代码来修复它:

<EditText
android:inputType="text"
android:digits="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" />

正如Florian Fröhlich所指出的那样,即使是对于文本视图,它也能很好地工作。

<TextView
android:inputType="text"
android:digits="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" />

小心提醒,android:digits中提到的字符仅用于显示,因此请务必小心不要漏掉任何一组字符 :)


你需要定义inputType="textFilter",才能使其正常工作。 - Shreyash Mahajan
@ShreyashMahajan,这取决于设备/键盘应用程序吗?在我的情况下,“inputType”不会影响过滤。 - CoolMind

7
除了已接受的答案之外,还可以使用如下方式:将android:inputType="textCapCharacters"作为<EditText>的属性,以仅接受大写字母(和数字)。

5
android:inputType="textCapCharacters"并不限制使用其他字符,比如“.,-”等。 - Tvd
它仅仅是输入法的提示,不限制可以输入哪些字符。 - dcow

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接