Як я можу використовувати InputFilter для обмеження символів в EditText в Android?


171

Я хочу обмежити символи лише 0-9, az, AZ та пробіл. Встановлення типу введення Я можу обмежитися цифрами, але я не можу визначити способи 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") фільтр повертається "", і жоден символ не з'являється в полі. Це пояснюється тим, що метод отримує SpannableStringBuilder у вихідному параметрі з "благом" у ньому та параметрами start / end, що охоплюють весь вхідний рядок ... Дивіться мою відповідь для кращого рішення.
Łukasz Sromek

4
У тому прикладі, де він повертається "", я думаю, що він повинен повернути текст, який повинен бути відображений. тобто вам слід видалити незаконні символи та повернути рядок, який Ви ХОЧУТЕ. developer.android.com/reference/android/widget/… , android.view.KeyEvent)
Ендрю Макензі

+1 Дійсно чудова відповідь. Character.isLetterOrDigit () всі ці методи дуже корисні.
Atul Bhardwaj

@AndrewMackenzie Якщо вхідний символ, наприклад, кома- ',', що не є законним, і я хочу його видалити, як виправити код вище.
twlkyao

! Character.isLetterOrDigit (source.charAt (i)) &&! Character.isSpaceChar (source.charAt (i)), щоб дозволити пробіли
Леон

139

InputFilters трохи складніші в версіях Android, які відображають пропозиції зі словника. Ви інколи отримуєте параметр a 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_\\-@]", "");
Бризок

3
Це не враховує проблему, де відображається текст повторення словника. @serwus визначив це у своїй відповіді. В основному вам слід повернути нуль, якщо в обох випадках не було внесено жодних змін.
hooby3dfx

3
Цей код ідеально працює, як сказав Лукас (у вищевказаній відповіді), але я зіткнувся з деякою проблемою з несловниковими словами. коли я набираю чіру, він показує 3 рази, як chiruchiruchiru. як це вирішити? і це займає пробіли, але як обмежити поруч із наступними пробілами?
чіру

3
Чомусь, коли source instanceof SpannableStringBuilderвведення АБ дає мені ААБ, як при спробі попередньої відповіді. На щастя, мені вдалося обійти це за допомогою рішення @florian нижче.
Гійом

1
@ hooby3dfx абсолютно прав. Незважаючи на те, що в результаті вдається отримати правильний рядок, він заплутається, коли ви використовуєте словник / слово завершення.
Аравінд

107

набагато простіше:

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

9
Хоча це здається ідеальною відповіддю, існує проблема згідно з документами: "Що стосується всіх реалізацій KeyListener, цей клас стосується лише апаратних клавіатур. Методи введення програмного забезпечення не зобов'язані запускати методи цього класу." Я думаю, що InputFilter - це, мабуть, кращий, хоч і складніший шлях.
Крейг Б

19
Дивовижне рішення Просто хочете додати Не потрібно поступатися ","між ними. Ви можете використовувати щось подібне"0123456789qwertzuiopasdfghjklyxcvbnmQWERTZUIOPASDFGHJKLYXCVBNM"
DeltaCap019,

26
Не багатомовне рішення
ААверин

Якщо ви плануєте використовувати переклади у своєму додатку. НЕ ВИКОРИСТОВУЙТЕ ЦЕ РІШЕННЯ!
грантспо

Схоже, це може не спрацювати 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

4
Єдине, що EditTextвже можуть мати власні фільтри, наприклад фільтр довжини. Тож замість того, щоб просто змінити фільтри, ви, швидше за все, хочете додати свої фільтри до вже існуючих.
Алекс Н.

Це все ще актуально? Для мене Android 6.0.1 працює на екранній клавіатурі
XxGoliathusxX

2
Невелика проблема з цією відповіддю (або з тим, як працює механізм введення Android) полягає в тому, що іноді користувачеві здається, що зворотна область не працює, оскільки вона проводить зворотні зміни за раніше введеними недійсними символами, які все ще знаходяться в буфері джерела.
jk7

1
Та ж проблема, що і з рішенням Лукаша Сромека: Недійсний символ після пробілу замінюється пробілом.
Інго Шалк-Шупп

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, Раді допомогти вам :)

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

Це насправді не задокументовано, але воно є частиною основної лібрики, і джерело є простим . Я використовую його деякий час зараз, до цих пір жодних проблем, хоча, зізнаюся, я не намагався робити щось складне, пов’язане з гайковими ключами.


5

Це правильно, найкращий спосіб вирішити це, щоб виправити це в самому макеті XML, використовуючи:

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

як справедливо зазначає Флоріан Фреліх, він добре працює навіть для перегляду тексту.

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

Просто слово обережності, символи, згадані у android:digitsзаповіті, будуть відображатися лише тому, будьте обережні, щоб не пропустити жодного набору символів :)


вам потрібно визначити inputType = "textFilter", тоді лише він буде працювати належним чином.
Шреяш Махаджан

@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 має один метод, filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) і він надає вам всю інформацію, яку вам потрібно знати про те, яким символам було введено в EditText, якому він призначений.

Після створення власного InputFilter ви можете призначити його EditText, зателефонувавши setFilters (...).

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проблемну реалізацію, я використовую TextWatcherі TextChangedListenerзEditText .

ПОВНИЙ КОД (ПРИКЛАД)

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- не гарне рішення в Android, оскільки це залежить від реалізації клавіатури. Вхід з клавіатури фільтрується до передачі входу до 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

Ось так я створив фільтр для поля "Ім'я" в редагуванні тексту. (Перша літера - це 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

Я маю таку ж відповідь у Котліні:

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

і отримати клас з функцією Extension:

fun EditText.filterByDataType(filterType: Int) {
    this.filters = arrayOf<InputFilter>(InputFilterAlphanumeric(filterType))
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.