InputFilterを使用してAndroidのEditTextの文字を制限するにはどうすればよいですか?


171

文字を0〜9、az、AZ、スペースバーのみに制限したい。inputtypeを設定すると、数字に制限できますが、ドキュメントを参照するInputfilterの方法を理解できません。

回答:


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"などの許可されている文字も)を入力した後フィルターは ""を返し、フィールドに文字は表示されません。これは、メソッドが "the-blah"を含むソースパラメータの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

InputFiltersは、辞書候補を表示する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_\\-@]", "");
Splash

3
これは、繰り返し辞書の提案テキストが表示される問題を考慮していません。@serwusは回答でそれを確認しました。どちらの場合も変更が行われない場合は、基本的にnullを返す必要があります。
hooby3dfx 2014

3
このコードは、lukaszが言ったように(上記の回答で)完全に機能しますが、非辞書の単語でいくつかの問題に直面しています。ちるとタイプすると、ちるちるちるのように3回表示されます。それを解決する方法?余白も必要ですが、次の余白をどのように制限するのですか?
chiru 2014

3
何らかの理由で、の場合source instanceof SpannableStringBuilderABを入力すると、前の回答を試すときのようにAABが表示されます。幸い、以下の@florianソリューションを使用することで回避できました。
ギヨーム

1
@ hooby3dfxは完全に正しいです。最終的に文字列を正しく管理することはできますが、辞書や単語の補完を使用すると混乱します。
Aravind 2014

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 2016

これはでは動作しないかもしれませんように思える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 2014

4
唯一のことは、EditText長さフィルターなどの独自のフィルターを既に持つことができます。そのため、フィルターを単にオーバーライドする代わりに、既存のフィルターにフィルターを追加することをお勧めします。
Aleks N. 2014

これはまだ最新ですか?私の場合、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、Happy to help you :)

1
これらの文字をブロックしません。㋡㋛☺☹☻〠シッツヅÜ〲〴ϡﭢت⍡⍢⍣⍤⍥⍨⍩ὃὕAnѶAn
Anarchofascist

7

受け入れられた回答に加えて、たとえばandroid:inputType="textCapCharacters"<EditText>大文字(および数字)のみを受け入れるためにの属性として使用することも可能です。


5
android:inputType = "textCapCharacters"は、 '。、-"などの他の文字の使用に制限し
ません

また、インプットメソッドへのヒントにすぎません。入力できる文字に制限はありません。
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インターフェースにはメソッドが1つあり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

edittext内の単語を防ぐため。uがいつでも使用できるクラスを作成します。

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

InputFilterAndroidでの適切なソリューションではない理由は、キーボードの実装に依存するためです。キーボード入力は、入力がに渡される前にフィルタリングされていEditTextます。ただし、一部のキーボードではInputFilter.filter()呼び出しの実装が異なるため、これには問題があります。

一方TextWatcher、キーボードの実装は気にせず、シンプルなソリューションを作成して、すべてのデバイスで動作することを確認できます。


onTextChanged単にそのpublic void前にが必要です。
アンディ

コメントをありがとう。修繕。
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

これは、[テキストの編集]の[名前]フィールドにフィルターを作成した方法です(最初の文字は大文字で、すべての単語の後にスペースを1つだけ入れます)。

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))
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.