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


171

我想将字符限制为0-9,az,AZ和空格键。设置输入类型I可以限制为数字,但是我无法弄清Inputfilter通过文档查找的方式。

Answers:


186

我在另一个论坛上找到了这个。像冠军一样工作。

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

58
实际上,它在较新的Android(如4.0+)中无法正常运行。他们在键盘上方介绍字典建议。当您键入一个常用词(例如“ the”)后跟一个非法字符(例如“-”)时,整个单词将被删除,并在您键入另一个字符(甚至允许的字符,例如“ blah”)之后过滤器返回“”,并且该字段中未显示任何字符。这是因为该方法在源参数中获取了一个带有“ theblah”的SpannableStringBuilder,并且起始/结束参数跨越了整个输入字符串...请参见我的答案以寻求更好的解决方案。
卢卡斯Sromek

4
在该示例中,它返回“”,我认为它应该返回应显示的文本。也就是说,您应该删除非法字符并返回您要显示的字符串。developer.android.com/reference/android/widget/...,android.view.KeyEvent)
安德鲁·麦肯齐

+1确实是一个很好的答案。Character.isLetterOrDigit()所有这些方法都非常有用。
Atul Bhardwaj 2013年

@AndrewMackenzie如果输入的字符(例如,逗号)不合法,而我想将其删除,则如何修复上面的代码。
twlkyao

!Character.isLetterOrDigit(source.charAt(i))&&!Character.isSpaceChar(source.charAt(i))允许留出空格
Leon

139

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

以下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_\\-@]", "");
飞溅

3
这没有考虑出现重复词典建议文本的问题。@serwus在他们的回答中指出了这一点。基本上,如果在两种情况下均未进行任何修改,则应返回null。
hooby3dfx

3
就像lukasz所说的那样,这段代码是完美的(在以上答案中),但是我在使用非字典词时遇到了一些问题。当我键入chiru时,它显示3次,就像chiruchiruchiru。怎么解决呢?并且它也需要空格,但是如何限制下一个空格?
chiru 2014年

3
由于某些原因,当source instanceof SpannableStringBuilder输入时,输入AB会给我AAB,就像尝试上一个答案时一样。幸运的是,我可以使用下面的@florian解决方案来解决此问题。
Guillaume 2014年

1
@ hooby3dfx是绝对正确的。虽然它确实设法使字符串最终正确,但是当您使用字典/单词完成功能时,它会弄乱。
Aravind

107

容易得多:

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

9
尽管这似乎是一个完美的答案,但是根据文档,存在一个问题:“对于KeyListener的所有实现,此类仅与硬件键盘有关。软件输入法没有义务触发此类中的方法。” 我认为InputFilter可能是更好的方法,尽管更复杂。
Craig B

19
很棒的解决方案只是想添加您不需要","在两者之间让步。您可以使用类似这样的东西"0123456789qwertzuiopasdfghjklyxcvbnmQWERTZUIOPASDFGHJKLYXCVBNM"
DeltaCap019

26
不是多语言解决方案
AAverin 2014年

如果您打算在应用程序中使用翻译。请勿使用此解决方案!
Grantespo

似乎无法使用imeOptions="actionNext"等等,等等
皮特·道尔

68

没有发布的答案对我有用。我有自己的解决方案:

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

4
唯一的事情是,EditText已经可以拥有自己的过滤器,例如长度过滤器。因此,您不仅希望覆盖过滤器,还很可能希望将过滤器添加到已经存在的过滤器中。
Aleks N.

这仍然是最新的吗?对我来说,Android 6.0.1可以在屏幕键盘上使用
XxGoliathusxX

2
这个答案(或Android的输入机制的工作方式)的一个小问题是,退格有时对用户来说似乎不起作用,因为退格是对仍保留在源缓冲区中的先前输入的无效字符进行退格。
jk7

1
与ŁukaszSromek解决方案相同的问题:空格后的无效字符被空格替换。
Ingo Schalk-Schupp

25

使用它的工作100%您的需要并且非常简单。

<EditText
android:inputType="textFilter"
android:digits="@string/myAlphaNumeric" />

在strings.xml中

<string name="myAlphaNumeric">abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789</string>

15

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

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

@sathya You wc,很乐意为您提供帮助:)

1
不阻止任何这些字符。ѶッッッѶAn An
Anarchofascist

7

除了接受的答案外,还可以使用例如:android:inputType="textCapCharacters"作为的属性,<EditText>以便仅接受大写字符(和数字)。


5
机器人:的inputType =“textCapCharacters”不列入限制到其它字符,如”,的使用- ”等。
TVD

这也只是对输入法的提示。它不限制允许输入什么字符。
dcow 2014年

5

由于某种原因,android.text.LoginFilter类的构造函数是包作用域的,因此您不能直接扩展它(即使它与这段代码相同)。但是您可以扩展LoginFilter.UsernameFilterGeneric!然后,您将拥有以下内容:

class ABCFilter extends LoginFilter.UsernameFilterGeneric {
    public UsernameFilter() {
        super(false); // false prevents not-allowed characters from being appended
    }

    @Override
    public boolean isAllowed(char c) {
        if ('A' <= c && c <= 'C')
            return true;
        if ('a' <= c && c <= 'c')
            return true;

        return false;
    }
}

确实没有记录,但是它是核心库的一部分,并且源代码很简单。我已经使用了一段时间了,到目前为止,没有问题,尽管我承认我还没有尝试做任何涉及跨度的复杂操作。


5

没错,最好的解决方法是使用以下方法在XML布局本身中进行修复:

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

正如FlorianFröhlich正确指出的那样,它甚至适用于文本视图。

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

请注意,android:digits只会显示中提到的字符,因此请注意不要错过任何字符集:)


您需要定义inputType =“ textFilter”,然后它才能正常工作。
Shreyash Mahajan

@ShreyashMahajan,它取决于设备/键盘应用程序吗?就我而言inputType,不影响过滤。
CoolMind

4

当我需要防止用户向EditText输入空字符串时,此简单的解决方案对我有用。您当然可以添加更多字符:

InputFilter textFilter = new InputFilter() {

@Override

public CharSequence filter(CharSequence c, int arg1, int arg2,

    Spanned arg3, int arg4, int arg5) {

    StringBuilder sbText = new StringBuilder(c);

    String text = sbText.toString();

    if (text.contains(" ")) {    
        return "";   
    }    
    return c;   
    }   
};

private void setTextFilter(EditText editText) {

    editText.setFilters(new InputFilter[]{textFilter});

}

这个解决方案怎么称呼?
zeeks

1

如果您将InputFilter子类化,则可以创建自己的InputFilter,以过滤掉所有非字母数字字符。

InputFilter接口只有一种方法,filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend)它为您提供了所有需要了解的信息,这些信息涉及哪些字符已输入到分配给它的EditText中。

创建自己的InputFilter之后,可以通过调用setFilters(...)将其分配给EditText。

http://developer.android.com/reference/android/text/InputFilter.html#filter(java.lang.CharSequence,int,int,android.text.Spanned,int,int


1

忽略其他人已经处理过的span东西,以正确处理字典建议,我发现以下代码有效。

来源随着建议的增长而增长,因此我们必须先查看它实际上期望我们替换多少个字符,然后再返回任何内容。

如果我们没有任何无效字符,则返回null,以便进行默认替换。

否则,我们需要从实际要放入EditText的子字符串中提取有效字符。

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

        boolean includesInvalidCharacter = false;
        StringBuilder stringBuilder = new StringBuilder();

        int destLength = dend - dstart + 1;
        int adjustStart = source.length() - destLength;
        for(int i=start ; i<end ; i++) {
            char sourceChar = source.charAt(i);
            if(Character.isLetterOrDigit(sourceChar)) {
                if(i >= adjustStart)
                     stringBuilder.append(sourceChar);
            } else
                includesInvalidCharacter = true;
        }
        return includesInvalidCharacter ? stringBuilder : null;
    } 
}; 

1

以防止edittext中的单词。创建一个您可以随时使用的类。

public class Wordfilter implements InputFilter
{
    @Override
    public CharSequence filter(CharSequence source, int start, int end,Spanned dest, int dstart, int dend) {
        // TODO Auto-generated method stub
        boolean append = false;
        String text = source.toString().substring(start, end);
        StringBuilder str = new StringBuilder(dest.toString());
        if(dstart == str.length())
        {
            append = true;
            str.append(text);
        }
        else
            str.replace(dstart, dend, text);
        if(str.toString().contains("aaaaaaaaaaaa/*the word here*/aaaaaaaa"))
        {
            if(append==true)
                return "";
            else
                return dest.subSequence(dstart, dend);
        }
        return null;
    }
}

1

首先添加到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


1

这是一个旧线程,但是有针对性的解决方案都有问题(取决于设备/ Android版本/键盘)。

不同的方法

所以,最终我去了不同的方法,而不是使用InputFilter有问题的实施,我使用TextWatcherTextChangedListenerEditText

完整代码(示例)

editText.addTextChangedListener(new TextWatcher() {

    @Override
    public void afterTextChanged(Editable editable) {
        super.afterTextChanged(editable);

        String originalText = editable.toString();
        int originalTextLength = originalText.length();
        int currentSelection = editText.getSelectionStart();

        // Create the filtered text
        StringBuilder sb = new StringBuilder();
        boolean hasChanged = false;
        for (int i = 0; i < originalTextLength; i++) {
            char currentChar = originalText.charAt(i);
            if (isAllowed(currentChar)) {
                sb.append(currentChar);
            } else {
                hasChanged = true;
                if (currentSelection >= i) {
                    currentSelection--;
                }
            }
        }

        // If we filtered something, update the text and the cursor location
        if (hasChanged) {
            String newText = sb.toString();
            editText.setText(newText);
            editText.setSelection(currentSelection);
        }
    }

    private boolean isAllowed(char c) {
        // TODO: Add the filter logic here
        return Character.isLetter(c) || Character.isSpaceChar(c);
    }
    @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) {
        // Do Nothing
    }
});

之所以InputFilter在Android中不是一个好的解决方案,是因为它取决于键盘的实现。在将键盘输入传递到之前对键盘输入进行过滤EditText。但是,由于某些键盘具有不同的InputFilter.filter()调用实现方式,因此存在问题。

另一方面,TextWatcher它并不关心键盘的实现,它使我们能够创建一个简单的解决方案,并确保它可以在所有设备上运行。


onTextChanged只需要一个public void它在前面。
安迪

感谢您的评论。固定。
伊亚·比兰

1

为了简化起见,我做了这样的事情:

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

0

可以使用setOnKeyListener。在这种方法中,我们可以自定义输入edittext


0

这就是我在“编辑文本”中为“名称”字段创建过滤器的方式。(第一个字母为CAPS,并且每个单词后只能有一个空格。

public void setNameFilter() {
    InputFilter filter = new InputFilter() {
        @RequiresApi(api = Build.VERSION_CODES.KITKAT)
        public CharSequence filter(CharSequence source, int start, int end,
                                   Spanned dest, int dstart, int dend) {
            for (int i = start; i < end; i++) {
                if (dend == 0) {
                    if (Character.isSpaceChar(source.charAt(i)) ||
                            !Character.isAlphabetic(source.charAt(i))) {
                        return Constants.Delimiter.BLANK;
                    } else {
                        return String.valueOf(source.charAt(i)).toUpperCase();
                    }
                } else if (Character.isSpaceChar(source.charAt(i)) &&
                        String.valueOf(dest).endsWith(Constants.Delimiter.ONE_SPACE)) {
                    return Constants.Delimiter.BLANK;
                } else if ((!Character.isSpaceChar(source.charAt(i)) &&
                        !Character.isAlphabetic(source.charAt(i)))) {
                    return Constants.Delimiter.BLANK;
                }
            }
            return null;
        }
    };
    editText.setFilters(new InputFilter[]{filter, new InputFilter.LengthFilter(Constants.Length.NAME_LENGTH)});
}

Constants.Delimiter.BLANK是未知的。
CoolMind

0

我在科特林有相同的答案:

/**
 * Returns the filter of the editText'es CharSequence value when [filterType] is:
 * 1 -> letters; 2 -> letters and digits; 3 -> digits;
 * 4 -> digits and dots
 */
class InputFilterAlphanumeric(private val filterType: Int): InputFilter {
    override fun filter(source: CharSequence?, start: Int, end: Int, dest: Spanned?, dstart: Int, dend: Int): CharSequence {
        (source as? SpannableStringBuilder)?.let {sourceAsSpannableBuilder  ->
            for (i in (end - 1) downTo start) {
                val currentChar = source[i]
                when(filterType) {
                    1 -> {
                        if (!currentChar.isLetter() && !currentChar.isWhitespace()) {
                            sourceAsSpannableBuilder.delete(i, i + 1)
                        }
                    }
                    2 -> {
                        if (!currentChar.isLetterOrDigit() && !currentChar.isWhitespace()) {
                            sourceAsSpannableBuilder.delete(i, i + 1)
                        }
                    }
                    3 -> {
                        if (!currentChar.isDigit()) {
                            sourceAsSpannableBuilder.delete(i, i + 1)
                        }
                    }
                    4 -> {
                        if (!currentChar.isDigit() || !currentChar.toString().contains(".")) {
                            sourceAsSpannableBuilder.delete(i, i + 1)
                        }
                    }
                }
            }
            return source
        } ?: run {
            val filteredStringBuilder = StringBuilder()
            for (i in start until end) {
                val currentChar = source?.get(i)
                when(filterType) {
                    1 -> {
                        if (currentChar?.isLetter()!! || currentChar.isWhitespace()) {
                            filteredStringBuilder.append(currentChar)
                        }
                    }
                    2 -> {
                        if (currentChar?.isLetterOrDigit()!! || currentChar.isWhitespace()) {
                            filteredStringBuilder.append(currentChar)
                        }
                    }
                    3 -> {
                        if (currentChar?.isDigit()!!) {
                            filteredStringBuilder.append(currentChar)
                        }
                    }
                    4 -> {
                        if (currentChar?.isDigit()!! || currentChar.toString().contains(".")) {
                            filteredStringBuilder.append(currentChar)
                        }
                    }
                }
            }
            return filteredStringBuilder
        }
    }
}

并使用扩展功能获取该类:

fun EditText.filterByDataType(filterType: Int) {
    this.filters = arrayOf<InputFilter>(InputFilterAlphanumeric(filterType))
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.