Bagaimana cara saya menggunakan InputFilter untuk membatasi karakter dalam EditText di Android?


171

Saya ingin membatasi karakter menjadi 0-9, az, AZ, dan bilah spasi saja. Mengatur tipe input I dapat membatasi ke angka tetapi saya tidak dapat menemukan cara-cara Inputfilter melihat melalui dokumen.

Jawaban:


186

Saya menemukan ini di forum lain. Bekerja seperti jagoan.

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
sebenarnya itu tidak berfungsi dengan baik di Android yang lebih baru (seperti 4.0+). Mereka memperkenalkan saran kamus di atas keyboard. Saat Anda mengetikkan kata umum (katakanlah "the") diikuti oleh karakter ilegal untuk filter ini (katakanlah, "-"), seluruh kata dihapus dan setelah Anda mengetikkan karakter lain (bahkan yang diizinkan, seperti "bla") filter mengembalikan "" dan tidak ada karakter yang muncul di lapangan. Ini karena metode ini mendapatkan SpannableStringBuilder dalam parameter sumber dengan "the-blah" di dalamnya dan mulai / akhir parameter yang mencakup seluruh string input ... Lihat jawaban saya untuk solusi yang lebih baik.
Łukasz Sromek

4
Dalam contoh itu, di mana ia mengembalikan "", saya pikir itu harus mengembalikan teks yang harus ditampilkan. yaitu Anda harus menghapus karakter ilegal dan mengembalikan string yang Anda inginkan ditampilkan. developer.android.com/reference/android/widget/… , android.view.KeyEvent)
Andrew Mackenzie

+1 Benar-benar jawaban yang bagus. Character.isLetterOrDigit () semua metode ini sangat berguna.
Atul Bhardwaj

@AndrewMackenzie Jika karakter input, misalnya, koma- ',', yang tidak legal, dan saya ingin menghapusnya, cara memperbaiki kode di atas.
twlkyao

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

139

InputFilters agak rumit dalam versi Android yang menampilkan saran kamus. Anda terkadang mendapatkan SpannableStringBuilder, terkadang polos Stringdi sourceparameter.

Berikut ini InputFilterharus bekerja. Jangan ragu untuk memperbaiki kode ini!

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
apakah ada alasan mengapa Anda tidak ingin melanjutkan sumbernya? Apakah Anda melihat ada yang salah dengan hanya melakukan ini (untuk hanya membolehkan alfanumerik ditambah beberapa karakter khusus): String replacement = source.subSequence(start, end).toString(); return replacement.replaceAll("[^A-Za-z0-9_\\-@]", "");
Splash

3
Ini tidak mempertimbangkan masalah di mana teks saran kamus berulang muncul. @serwus mengidentifikasi itu dalam jawaban mereka. Pada dasarnya Anda harus mengembalikan nol jika tidak ada modifikasi yang dilakukan dalam kedua kasus.
hooby3dfx

3
Kode ini berfungsi sempurna seperti kata lukasz (dalam jawaban di atas) tetapi saya menghadapi beberapa masalah dengan kata-kata non-kamus. ketika saya mengetik chiru itu menunjukkan 3 kali seperti chiruchiruchiru. bagaimana cara mengatasinya? dan itu mengambil ruang putih juga, tetapi bagaimana membatasi di sebelah ruang putih berikutnya?
chiru

3
Untuk beberapa alasan, ketika source instanceof SpannableStringBuilder, memasuki AB memberi saya AAB seperti ketika mencoba jawaban sebelumnya. Untungnya saya bisa mengatasinya dengan menggunakan solusi @florian di bawah ini.
Guillaume

1
@ hooby3dfx benar sekali. Meskipun tidak berhasil mendapatkan string pada akhirnya, itu mengacaukan ketika Anda menggunakan kamus / penyelesaian kata.
Aravind

107

jauh lebih mudah:

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

9
Meskipun ini sepertinya jawaban yang sempurna, ada masalah menurut dokumen: "Adapun semua implementasi KeyListener, kelas ini hanya berkaitan dengan keyboard perangkat keras. Metode input perangkat lunak tidak memiliki kewajiban untuk memicu metode di kelas ini." Saya pikir InputFilter mungkin cara yang lebih baik, meskipun lebih rumit.
Craig B

19
Solusi Luar Biasa Hanya Ingin Menambahkan Anda tidak perlu menyerah ","di antara keduanya. Anda dapat menggunakan sesuatu seperti ini"0123456789qwertzuiopasdfghjklyxcvbnmQWERTZUIOPASDFGHJKLYXCVBNM"
DeltaCap019

26
Bukan solusi multibahasa
AAverin

Jika Anda berencana menggunakan terjemahan di aplikasi Anda. JANGAN GUNAKAN SOLUSI INI!
grantespo

Sepertinya ini mungkin tidak berhasil imeOptions="actionNext", dll.
Pete Doyle

68

Tidak ada jawaban yang diposting yang berfungsi untuk saya. Saya datang dengan solusi saya sendiri:

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
Ini adalah satu-satunya jawaban yang benar-benar memiliki pendekatan yang tepat untuk mencegah pengulangan teks dari saran kamus! Suara positif!
hooby3dfx

4
Satu-satunya hal, EditTextsudah dapat memiliki filter sendiri, mis. Filter panjang. Jadi, alih-alih hanya mengganti filter, Anda kemungkinan besar ingin menambahkan filter Anda ke yang sudah ada.
Aleks N.

Apakah ini masih terkini? Bagi saya Android 6.0.1 berfungsi pada keyboard layar
XxGoliathusxX

2
Masalah kecil dengan jawaban ini (atau dengan bagaimana mekanisme input Android bekerja) adalah bahwa backspace kadang-kadang muncul bagi pengguna untuk tidak berfungsi karena mereka melakukan backspacing atas karakter yang dimasukkan sebelumnya yang tidak valid yang masih ditahan di buffer sumber.
jk7

1
Masalah yang sama dengan solusi Łukasz Sromek: Karakter yang tidak valid setelah spasi diganti dengan spasi.
Ingo Schalk-Schupp

25

Gunakan ini kerjanya 100% kebutuhan Anda dan sangat sederhana.

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

Di strings.xml

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

15

Untuk menghindari Karakter Khusus dalam tipe input

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

Anda dapat mengatur filter ke teks edit Anda seperti di bawah ini

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

@sathya You wc, Senang membantu Anda :)

1
Tidak memblokir salah satu dari karakter ini. ㋡ ㋛ ☺ ☹ ☻ 〠 シ ッ ツ ツ Ü Ü Ü Ü ﭢ ت ت ت ت ت Ѷ Ѷ Ѷ An An An
Anarchofascist

7

Selain jawaban yang diterima, dimungkinkan juga untuk menggunakan misalnya: android:inputType="textCapCharacters"sebagai atribut <EditText>agar hanya menerima karakter huruf besar (dan angka).


5
android: inputType = "textCapCharacters" tidak membatasi penggunaan karakter lain seperti '., - "dll.
Tvd

Ini juga hanya petunjuk untuk metode input. Itu tidak membatasi karakter apa yang diizinkan untuk dimasukkan.
dcow

5

Untuk beberapa alasan konstruktor kelas android.text.LoginFilter adalah paket-lingkup, sehingga Anda tidak dapat langsung memperpanjangnya (meskipun itu akan identik dengan kode ini). Tetapi Anda dapat memperpanjang LoginFilter.UsernameFilterGeneric! Maka Anda hanya memiliki ini:

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

Ini tidak benar-benar didokumentasikan, tetapi itu adalah bagian dari inti lib, dan sumbernya langsung . Saya telah menggunakannya untuk sementara waktu sekarang, sejauh ini tidak ada masalah, meskipun saya akui saya belum mencoba melakukan sesuatu yang rumit yang melibatkan spannables.


5

Itu Benar, cara terbaik untuk memperbaikinya untuk memperbaikinya dalam Layout XML menggunakan:

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

sebagaimana ditunjukkan oleh Florian Fröhlich, ini berfungsi dengan baik untuk tampilan teks yang rata.

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

Hanya kata hati-hati, karakter yang disebutkan dalam android:digitshanya akan ditampilkan, jadi berhati-hatilah untuk tidak melewatkan serangkaian karakter :)


Anda perlu mendefinisikan inputType = "textFilter" maka hanya itu yang akan berfungsi dengan baik.
Shreyash Mahajan

@ShreyashMahajan, apakah ini tergantung pada aplikasi perangkat / keyboard? Dalam kasus saya inputTypetidak mempengaruhi pemfilteran.
CoolMind

4

Solusi sederhana ini bekerja untuk saya ketika saya perlu mencegah pengguna memasukkan string kosong ke dalam EditText. Tentu saja Anda dapat menambahkan lebih banyak karakter:

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

}

bagaimana cara memanggil solusi ini?
zeeks

1

Jika Anda subkelas InputFilter Anda dapat membuat InputFilter Anda sendiri yang akan memfilter karakter non-alfa-numerik.

InputFilter Interface memiliki satu metode,, filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend)dan menyediakan Anda dengan semua informasi yang perlu Anda ketahui tentang karakter yang dimasukkan ke dalam EditText yang ditugaskan padanya.

Setelah Anda membuat InputFilter Anda sendiri, Anda dapat menetapkannya ke EditText dengan memanggil setFilters (...).

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


1

Mengabaikan hal-hal rentang yang telah ditangani orang lain, untuk menangani saran kamus dengan benar, saya menemukan kode berikut berfungsi.

Sumber tumbuh seiring saran tumbuh sehingga kita harus melihat berapa banyak karakter yang sebenarnya diharapkan untuk kita ganti sebelum kita mengembalikan apa pun.

Jika kami tidak memiliki karakter yang tidak valid, kembalikan null sehingga terjadi penggantian default.

Kalau tidak, kita perlu mengekstraksi karakter yang valid dari substring yang SEBENARNYA akan ditempatkan ke dalam 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

untuk mencegah kata-kata dalam edittext. buat kelas yang bisa Anda gunakan kapan saja.

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

Pertama tambahkan strings.xml:

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

XML :

android:digits="@string/vin_code_mask"

Kode di 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
}

Aneh, tetapi bekerja aneh pada keyboard lunak emulator.

Peringatan! Kode berikut akan memfilter semua huruf dan simbol lainnya kecuali angka untuk keyboard perangkat lunak. Hanya keyboard digital yang akan muncul di smartphone.

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

Saya juga biasanya ditetapkan maxLength, filters, inputType.


1

Ini adalah utas lama, tetapi solusi yang dimaksudkan semuanya memiliki masalah (tergantung pada perangkat / versi Android / Keyboard).

PENDEKATAN YANG BERBEDA

Jadi akhirnya aku pergi dengan pendekatan yang berbeda, daripada menggunakan InputFilterimplementasi bermasalah, saya menggunakan TextWatcherdan TextChangedListenerdari EditText.

KODE LENGKAP (CONTOH)

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

Alasannya InputFilterbukan solusi yang baik di Android karena itu tergantung pada implementasi keyboard. Input Keyboard sedang difilter sebelum input dilewatkan ke EditText. Tetapi, karena beberapa keyboard memiliki implementasi yang berbeda untuk InputFilter.filter()permohonan, ini bermasalah.

Di sisi lain TextWatchertidak peduli dengan implementasi keyboard, itu memungkinkan kami untuk membuat solusi sederhana dan memastikan itu akan bekerja pada semua perangkat.


The onTextChangedhanya membutuhkan public voiddepan di itu.
Andy

Terima kasih atas komentarnya. Tetap.
Eyal Biran

1

Saya telah melakukan sesuatu seperti ini untuk membuatnya tetap sederhana:

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 ]"), "")
    }
})

Dengan cara ini kami mengganti semua karakter yang tidak diinginkan di bagian baru dari string sumber dengan string kosong.

The edit_textvariabel adalah EditTextobjek kita mengacu kepada.

Kode ditulis dalam bahasa kotlin.


1
Terima kasih! Solusi ini berfungsi baik saat mengetik maupun menempelkan teks.
CoolMind

0

Dimungkinkan untuk digunakan setOnKeyListener. Dalam metode ini, kita dapat menyesuaikan input edittext!


0

Inilah cara saya membuat filter untuk bidang Nama di Edit Teks. (Huruf pertama adalah CAPS, dan hanya mengizinkan satu spasi setelah setiap kata.

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 tidak dikenal.
CoolMind

0

Saya memiliki jawaban yang sama di 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
        }
    }
}

dan dapatkan kelas dengan fungsi Extension:

fun EditText.filterByDataType(filterType: Int) {
    this.filters = arrayOf<InputFilter>(InputFilterAlphanumeric(filterType))
}
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.