Android'de bir EditText'teki karakterleri sınırlamak için InputFilter'ı nasıl kullanabilirim?


171

Karakterleri sadece 0-9, az, AZ ve ara çubuğu ile sınırlamak istiyorum. Giriş türü I'nin ayarlanması basamaklarla sınırlanabilir, ancak Giriş Filtresi'nin dokümanlara bakma yollarını bulamıyorum.

Yanıtlar:


186

Bunu başka bir forumda buldum. Bir şampiyon gibi çalışır.

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
aslında yeni Android'lerde (4.0+ gibi) iyi çalışmıyor. Klavyenin üzerinde sözlük önerileri getiriyorlar. Bu filtre için ortak bir kelime ("" "diyelim) ve ardından geçersiz bir karakter (diyelim" - "diyelim) yazdığınızda, tüm kelime silinir ve başka bir karakter (" blah "gibi izin verilenler bile) yazıldıktan sonra filtre "" döndürür ve alanda hiçbir karakter görünmez. Bunun nedeni, yöntemin kaynak parametresinde "the-blah" bulunan bir SpannableStringBuilder alması ve tüm girdi dizesini kapsayan start / end parametreleri ... Daha iyi bir çözüm için cevabımı görün.
asukasz Sromek

4
"" Döndürdüğü örnekte, görüntülenmesi gereken metni döndürmesi gerektiğini düşünüyorum. yani, geçersiz karakterleri kaldırmalı ve görüntülenmesini istediğiniz dizeyi döndürmelisiniz. developer.android.com/reference/android/widget/… , android.view.KeyEvent)
Andrew Mackenzie

+1 Gerçekten harika bir cevap. Character.isLetterOrDigit () tüm bu yöntemler çok kullanışlıdır.
Atul Bhardwaj

@AndrewMackenzie Giriş karakteri, örneğin, yasal olmayan bir virgül 've' varsa ve kaldırmak istiyorum, yukarıdaki kodu nasıl düzeltebilirim.
twlkyao

! Character.isLetterOrDigit (source.charAt (i)) &&! Character.isSpaceChar (source.charAt (i)) boşluklara izin vermek için
Leon

139

InputFilterSözlük önerilerini görüntüleyen Android sürümlerinde biraz karmaşıktır. Bazen bir olsun SpannableStringBuilder, bazen sade Stringiçinde sourceparametresi.

Devamındaki InputFilter çalışması gerekir. Bu kodu geliştirmekten çekinmeyin!

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
kaynağı takip etmek istememenizin bir nedeni var mı? Sadece bunu yapmakla ilgili yanlış bir şey görüyor musunuz (sadece alfasayısallara ve birkaç özel karaktere izin vermek için): String replacement = source.subSequence(start, end).toString(); return replacement.replaceAll("[^A-Za-z0-9_\\-@]", "");
Splash

3
Bu, tekrarlanan sözlük öneri metninin ortaya çıktığı bir sorunu dikkate almaz. @serwus cevaplarında bunu belirledi. Her iki durumda da değişiklik yapılmazsa, temel olarak null değerini döndürmelisiniz.
hooby3dfx

3
Bu kod lukasz (yukarıdaki cevapta) dedi gibi mükemmel çalışır, ancak sözlük olmayan kelimeler ile bazı sorunla karşı karşıyayım. Ben chiru yazdığınızda chiruchiruchiru gibi 3 kez gösterir. Nasıl çözeceksin? ve beyaz boşlukları da alıyor ama sonraki beyaz boşlukların yanında nasıl kısıtlanır?
chiru

3
Bir nedenden ötürü, AB'yesource instanceof SpannableStringBuilder girerken önceki cevabı denerken bana AAB'yi verir . Neyse ki aşağıdaki @florian çözümünü kullanarak bu sorunu çözebildim.
Guillaume

1
@ hooby3dfx kesinlikle doğru. Sonunda dizeyi doğru almayı başarsa da, sözlük / kelime tamamlama kullandığınızda bozulur.
Aravind

107

daha kolay:

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

9
Bu mükemmel bir yanıt gibi görünse de, belgelere göre bir sorun var: "KeyListener'ın tüm uygulamalarında olduğu gibi, bu sınıf sadece donanım klavyeleriyle ilgilidir. Yazılım giriş yöntemlerinin bu sınıftaki yöntemleri tetikleme zorunluluğu yoktur." Ben bir InputFilter muhtemelen daha karmaşık olsa da, daha iyi bir yol olduğunu düşünüyorum.
Craig B

19
Harika bir çözüm Sadece eklemek istiyorum ","Aralarında vermek zorunda değilsiniz . Böyle bir şey kullanabilirsiniz"0123456789qwertzuiopasdfghjklyxcvbnmQWERTZUIOPASDFGHJKLYXCVBNM"
DeltaCap019

26
Çok dilli bir çözüm değil
AAverin

Uygulamanızda çevirileri kullanmayı planlıyorsanız. BU ÇÖZÜMÜ KULLANMAYIN!
grantespo

Bu imeOptions="actionNext", vb.
Pete Doyle

68

Gönderilen cevapların hiçbiri benim için işe yaramadı. Kendi çözümümle geldim:

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
Sözlük önerilerinden metni tekrar etmeyi önlemek için doğru yaklaşıma sahip tek cevap budur! Oyla!
hooby3dfx

4
Tek şey, EditTextkendi filtrelerine sahip olabilir, örneğin uzunluk filtresi. Bu nedenle, filtreleri geçersiz kılmak yerine, büyük olasılıkla filtrelerinizi zaten mevcut olanlara eklemek istersiniz.
Aleks N.

Bu hala güncel mi? Benim için Android 6.0.1, ekran klavyesinde çalışıyor
XxGoliathusxX

2
Bu yanıtla (veya Android'in giriş mekanizmasının nasıl çalıştığına dair) küçük bir sorun, geri aracının bazen kaynak tamponda tutulan daha önce girilen geçersiz karakterler üzerinde geri döndüğü için kullanıcıya çalışmıyor gibi görünmesidir.
jk7

1
Asukasz Sromek'in çözümü ile aynı problem: Bir boşluktan sonra geçersiz bir karakter bir boşlukla değiştirilir.
Ingo Schalk-Schupp

25

Bu işi% 100 ihtiyaç ve çok basit kullanın.

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

Strings.xml dosyasında

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

15

Giriş türünde Özel Karakterlerden kaçınmak için

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

Düzenleme metninize aşağıdaki gibi filtre ayarlayabilirsiniz

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

@sathya You wc, Size yardımcı

1
Bu karakterlerin hiçbirini engellemez. ㋡ ㋛ ☺ ☹ ☻ 〠シッツヅÜ 〲 〴 ϡ ٿ ت ⍡ ⍢ ⍣
Anarchofascist

7

Kabul edilen cevaba ek olarak, sadece büyük harf karakterleri (ve sayıları) kabul etmek için örneğin: özelliği android:inputType="textCapCharacters"olarak da kullanılabilir <EditText>.


5
android: inputType = "textCapCharacters", '., - "vb. gibi diğer karakterlerin kullanımını kısıtlamaz
Tvd

Ayrıca, giriş yöntemine sadece bir ipucu. Hangi karakterlerin girilmesine izin verildiğini kısıtlamaz.
dcow

5

Herhangi bir nedenle android.text.LoginFilter sınıfının yapıcısı paket kapsamlıdır, bu nedenle doğrudan genişletemezsiniz (bu kodla aynı olsa bile). Ancak LoginFilter.UsernameFilterGeneric! Sonra sadece bu var:

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

Bu gerçekten belgelenmemiştir, ancak çekirdek lib'in bir parçasıdır ve kaynak basittir . Bir süredir kullanıyorum, şimdiye kadar sorun yok, ancak spannable'ları içeren karmaşık bir şey yapmayı denemediğimi itiraf ediyorum.


5

Doğru, bunu kullanarak XML Düzeninde düzeltmek için en iyi yol:

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

Florian Fröhlich'in haklı olarak işaret ettiği gibi, metin görünümleri için bile iyi çalışıyor.

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

Dikkatli bir kelime, belirtilen karakterler android:digitssadece görüntülenecektir, bu yüzden herhangi bir karakter kümesini kaçırmamaya dikkat edin :)


inputType = "textFilter" tanımlamanız gerekiyorsa, yalnızca düzgün çalışacaktır.
Shreyash Mahajan

@ShreyashMahajan, cihaza / klavye uygulamasına bağlı mı? Benim durumumda inputTypefiltrelemeyi etkilemez.
CoolMind

4

Kullanıcının bir EditText içine boş dizeler girmesini önlemek gerektiğinde bu basit çözüm benim için çalıştı. Elbette daha fazla karakter ekleyebilirsiniz:

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

}

bu çözüm nasıl adlandırılır?
zeeks

1

InputFilter alt sınıfını yaparsanız, alfasayısal olmayan karakterleri filtreleyecek kendi InputFilter öğenizi oluşturabilirsiniz.

InputFilter Arabirimi'nin bir yöntemi vardır filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend)ve size hangi karakterlerin atandığı EditText'e girildiğiyle ilgili bilmeniz gereken tüm bilgileri sağlar.

Kendi InputFilter öğenizi oluşturduktan sonra, setFilters (...) öğesini çağırarak Filtreyi EditText'e atayabilirsiniz.

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


1

Diğer insanların uğraştığı span şeylerini göz ardı ederek, sözlük önerilerini doğru bir şekilde işlemek için aşağıdaki kod çalışmalarını buldum.

Öneri büyüdükçe kaynak büyüyor, bu yüzden herhangi bir şeyi iade etmeden önce aslında kaç karakter bizi değiştirmemizi beklediğine bakmalıyız.

Geçersiz karakterimiz yoksa, varsayılan değiştirmenin gerçekleşmesi için null değerini döndürün.

Aksi takdirde, GERÇEKTEN EditText'e yerleştirilecek olan alt dizeden geçerli karakterleri çıkarmamız gerekir.

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'de kelimeleri önlemek için. u istediğiniz zaman kullanabileceğiniz bir sınıf oluşturun.

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

Önce şunu ekleyin strings.xml:

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

XML :

android:digits="@string/vin_code_mask"

Kotlin'de Kod :

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
}

Garip, ama emülatörün yumuşak klavyesinde garip bir şekilde çalışıyor.

Uyarı! Aşağıdaki kod, yazılım klavyelerinin rakamları dışındaki tüm harfleri ve diğer simgeleri filtreleyecektir. Akıllı telefonlarda yalnızca dijital klavye görünecektir.

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

Ben de genellikle set maxLength, filters, inputType.


1

Bu eski bir iş parçacığıdır, ancak amaçlanan çözümlerin hepsinin sorunları vardır (cihaza / Android sürümüne / Klavyeye bağlı olarak).

FARKLI YAKLAŞIM

Yani sonuçta ben kullanmak yerine, farklı bir yaklaşımla gitti InputFilter, sorunlu uygulanmasını kullanıyorum TextWatcherve TextChangedListenerbir EditText.

TAM KOD (ÖRNEK)

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

Nedeni InputFilter, Android'de iyi bir çözüm değildir, çünkü klavye uygulamasına bağlıdır. Klavye girişi, girişe geçirilmeden önce filtreleniyor EditText. Ancak, bazı klavyelerin InputFilter.filter()çağırma için farklı uygulamaları olduğundan , bu sorunludur.

Öte yandan TextWatcherklavye uygulamasını önemsemiyor, basit bir çözüm oluşturmamıza ve tüm cihazlarda çalışacağından emin olmamıza izin veriyor.


onTextChangedSadece ihtiyacı public voido cepheyi.
Andy

Yorum için teşekkürler. Sabit.
Eyal Biran

1

Basit tutmak için böyle bir şey yaptım:

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

Bu şekilde, kaynak dizenin yeni bölümündeki tüm istenmeyen karakterleri boş bir dizeyle değiştiriyoruz.

edit_textDeğişkendir EditTextPeki bahsettiğimiz nesnesi.

Kod yazılmıştır kotlin.


1
Teşekkürler! Bu çözüm, metin yazarken ve yapıştırırken iyi çalışır.
CoolMind

0

Kullanmak mümkündür setOnKeyListener. Bu yöntemde girişi özelleştirebiliriz edittext!


0

Metni Düzenle'deki Ad alanı için filtreyi bu şekilde oluşturdum. (İlk harf CAPS'tir ve her sözcükten sonra yalnızca tek bir boşluğa izin verir.

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 bilinmemektedir.
CoolMind

0

Kotlin'de de aynı cevabım var:

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

ve bir eklenti işleviyle sınıfı edinin:

fun EditText.filterByDataType(filterType: Int) {
    this.filters = arrayOf<InputFilter>(InputFilterAlphanumeric(filterType))
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.