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

194

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

20个回答

7

您可以在正则表达式中指定想要的字符,并在InputFilter中使用它:

val regex = Regex("[a-zA-Z\\d ]")
    
editText.filters = arrayOf(InputFilter { source, _, _, _, _, _ ->
    source.filter { regex.matches(it.toString()) }
})

注意,我没有使用\w字符类,因为它包括下划线_


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

这个并没有详细说明,但是它是核心库的一部分,并且源码很简单。我已经使用了一段时间了,目前还没有遇到问题,虽然我承认我还没有尝试过涉及的复杂操作。


4

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

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

2

这是一个旧的帖子,但是提出的解决方案都存在问题(取决于设备/Android版本/键盘)。

不同的方法

最终我采用了一种不同的方法,而不是使用有问题的InputFilter实现,我使用了EditTextTextWatcherTextChangedListener

完整代码(示例)

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
    }
});
< p > InputFilter 不是 Android 中的好解决方案,因为它依赖于键盘实现。在输入传递到 EditText 之前,键盘输入被过滤。但是,由于一些键盘对 InputFilter.filter() 调用有不同的实现,这是有问题的。

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


onTextChanged 方法只需要在前面加上 public void - user2711811

1
忽略其他人处理的跨度问题,为了正确处理字典建议,我发现以下代码有效。
当建议增加时,源代码也会增长,因此我们必须看一下它实际上期望我们替换多少个字符,然后再返回任何内容。
如果没有任何无效字符,则返回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

如果你子类化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)


0

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


0
这是我如何为EditText中的Name字段创建过滤器的方法。(首字母大写,并且每个单词后只允许一个空格。)
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)});
}

常量.Delimiter.BLANK未知。 - CoolMind

0

我在 Kotlin 中有相同的答案:

/**
 * 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))
}

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