Android에서 EditText의 문자를 제한하기 위해 InputFilter를 어떻게 사용합니까?


171

문자를 0-9, az, AZ 및 스페이스 바로 제한하고 싶습니다. 입력 유형을 설정하면 숫자로 제한 할 수 있지만 입력 필터가 문서를 살펴 보는 방법을 알 수 없습니다.

답변:


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
실제로 4.0 이상과 같은 최신 Android에서는 제대로 작동하지 않습니다. 키보드 위에 사전 제안을 소개합니다. 일반적인 단어 ( "the"라고 말함)와이 필터에 대해 잘못된 문자 (예 : "-")를 입력하면 전체 단어가 삭제되고 다른 문자 ( "blah"와 같이 허용되는 문자)를 입력하면 전체 단어가 삭제됩니다 필터는 ""를 반환하고 필드에 문자가 표시되지 않습니다. 메서드가 소스 매개 변수에 "the-blah"가 포함 된 SpannableStringBuilder를 가져와 전체 입력 문자열에 걸쳐 시작 / 종료 매개 변수를 가져 오기 때문입니다. 더 나은 솔루션은 내 답변을 참조하십시오.
Łukasz Sromek

4
이 예에서 ""를 반환하는 경우 표시해야 할 텍스트를 반환해야한다고 생각합니다. 즉, 잘못된 문자를 제거하고 원하는 문자열을 반환해야합니다. developer.android.com/reference/android/widget/… , android.view.KeyEvent)
Andrew Mackenzie

+1 정말 좋은 답변입니다. Character.isLetterOrDigit ()이 모든 메소드는 매우 유용합니다.
Atul Bhardwaj

@AndrewMackenzie 입력 문자 (예 : 쉼표 ',')가 유효하지 않은 경우 제거하고 싶습니다. 위의 코드를 수정하는 방법.
twlkyao

! Character.isLetterOrDigit (source.charAt (i)) &&! Character.isSpaceChar (source.charAt (i))
Leon

139

InputFilter사전 제안을 표시하는 Android 버전에서는 약간 복잡합니다. 때로는 매개 변수 에 SpannableStringBuilder, 때로는 일반 String이 표시 source됩니다.

다음 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 2019

3
이 코드는 lukasz가 (위 답변에서) 말했듯이 완벽하게 작동하지만 비 사전 단어에 문제가 있습니다. chiru를 입력하면 chiruchiruchiru와 같은 3 배가 표시됩니다. 그것을 해결하는 방법? 공백도 필요하지만 다음 공백 옆을 제한하는 방법은 무엇입니까?
chiru

3
어떤 이유로, 때 ABsource instanceof SpannableStringBuilder입력 하면 이전 답변을 시도 할 때와 같은 AAB 가 표시됩니다. 다행히 아래의 @florian 솔루션을 사용하여 해결할 수있었습니다.
기 illa

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

앱에서 번역을 사용하려는 경우. 이 솔루션을 사용하지 마십시오!
grantespo

이와 같이 작동하지 않는 것 같습니다 imeOptions="actionNext".
Pete Doyle

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.

여전히 최신 상태입니까? 나를 위해 안드로이드 6.0.1 그것은 화면 키보드에서 작동
XxGoliathusxX

2
이 답변 (또는 Android의 입력 메커니즘 작동 방식)의 사소한 문제는 백 스페이스가 여전히 소스 버퍼에 남아있는 이전에 입력 한 유효하지 않은 문자보다 백 스페이싱하기 때문에 사용자에게 작동하지 않는 것처럼 보입니다.
jk7

1
Łukasz Sromek의 솔루션과 동일한 문제 : 공백 다음에 잘못된 문자가 공백으로 바뀝니다.
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 당신 화장실, 당신을 도울 수 :)

1
이러한 문자를 차단하지 않습니다. ㋡ ㋛ ☺ ☹ ☻ 〠 シ ッ ツ ヅ Ü 〲 〴 ϡ ﭢ ت ⍡ ⍢ ⍣ ⍤ ⍥ ⍨ ⍩ ὃ ὕ ὣ Ѷ
Anarchofascist

7

허용되는 답변 외에도 대문자 (및 숫자) 만 허용하기 위해 예를 들어 android:inputType="textCapCharacters"속성을 속성으로 사용할 수도 있습니다 <EditText>.


5
android : inputType = "textCapCharacters"는 '.,-'등과 같은 다른 문자의 사용으로 제한되지 않습니다.
Tvd

또한 입력 방법에 대한 힌트 일뿐입니다. 입력 할 수있는 문자를 제한하지 않습니다.
dcow

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

이것은 실제로 문서화되어 있지는 않지만 핵심 lib의 일부이며 소스는 간단 합니다. 나는 지금까지 그것을 사용해 왔지만 지금까지 아무런 문제가 없었지만 스패너 블과 관련된 복잡한 작업은 시도하지 않았다는 것을 인정합니다.


5

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

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 Interface에는 한 가지 메소드가 있으며 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

다른 사람들이 다루었던 범위를 무시하고 사전 제안을 올바르게 처리하기 위해 다음 코드가 작동한다는 것을 알았습니다.

제안이 커짐에 따라 소스가 커지므로 아무 것도 반환하기 전에 실제로 얼마나 많은 문자를 교체해야하는지 확인해야합니다.

유효하지 않은 문자가 없으면 기본 대체가 발생하도록 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

편집 텍스트에서 단어를 방지합니다. 언제든 사용할 수있는 클래스를 만듭니다.

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"

코 틀린 코드 :

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

또한 일반적으로 설정 maxLength, filters, inputType.


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는 키보드 구현에 달려 있기 때문에 안드로이드에서 좋은 해결책이 아닙니다. 입력이로 전달되기 전에 키보드 입력이 필터링 EditText됩니다. 그러나 일부 키보드는 InputFilter.filter()호출에 대해 구현이 다르기 때문에 문제가 있습니다.

반면 TextWatcher키보드 구현에 신경 쓰지 않으면 간단한 솔루션을 만들고 모든 장치에서 작동하는지 확인할 수 있습니다.


onTextChanged단순히 필요 public void그것의에서 앞.
Andy

의견 주셔서 감사합니다. 결정된.
Eyal Biran

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

나는 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))
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.