Android: как я могу проверить ввод EditText?

Мне нужно выполнить проверку ввода формы в серии EditTexts. Я использую OnFocusChangeListeners для запуска проверки после ввода пользователем каждого из них, но это не работает должным образом для последнего EditText.

Если я нажимаю кнопку «Готово» при вводе окончательного EditText, тогда InputMethod отключается, но технически фокус никогда не теряется на EditText (и поэтому проверка никогда не происходит).

Какое лучшее решение?

Должен ли я отслеживать, когда InputMethod отсоединяется от каждого EditText, а не когда изменяется фокус? Если да, то как?


person Stefan    schedule 04.05.2010    source источник
comment
Вам действительно нужно проверять ввод EditText в то же время, когда пользователь печатает? Почему бы вам просто не проверить EditText, как только пользователь нажмет кнопку «Готово»?   -  person Cristian    schedule 04.05.2010
comment
Это именно то, что я хочу: чтобы текст проверялся, когда пользователь нажимает кнопку «Готово» (под кнопкой «Готово» я имею в виду кнопку «Готово» в QWERTY InputManager... НЕ кнопку отправки формы). За исключением того, что когда я нажимаю кнопку «Готово», фокус остается на последнем элементе в форме, и мой метод проверки никогда не запускается. Надеюсь, моя формулировка понятна...   -  person Stefan    schedule 05.05.2010
comment
Решение @Cristian — это именно то, что я искал, и его можно найти здесь: stackoverflow.com/questions/43013812/   -  person LampPost    schedule 16.11.2018
comment
@Cristian Немного поздно, но я ищу решение, в котором EditText проверяется пока человек печатает. У меня есть форма входа/регистрации, и я хочу показывать кнопку "Отправить" только, когда данные формы действительны.   -  person Zonker.in.Geneva    schedule 20.04.2020


Ответы (14)


Почему бы вам не использовать TextWatcher ?

Поскольку у вас есть несколько EditText ящиков для проверки, я думаю, вам подойдет следующее:

  1. Ваша активность реализует android.text.TextWatcher интерфейс
  2. Вы добавляете слушателей TextChanged в свои поля EditText
txt1.addTextChangedListener(this);
txt2.addTextChangedListener(this);
txt3.addTextChangedListener(this);
  1. Из переопределенных методов вы можете использовать метод afterTextChanged(Editable s) следующим образом
@Override
public void afterTextChanged(Editable s) {
    // validation code goes here
}

Editable s на самом деле не помогает определить, текст какого поля EditText изменяется. Но вы можете напрямую проверить содержимое полей EditText, например

String txt1String = txt1.getText().toString();
// Validate txt1String

тем же методом. Я надеюсь, что я ясно, и если я, это помогает! :)

EDIT: более чистый подход см. в ответе Кристофера Перри ниже.

person Niks    schedule 18.05.2010
comment
Похоже, это именно то, что мне нужно. Не слышал о TextWatcher (новичок в SDK/API), но я протестирую его и посмотрю, будет ли он вести себя так, как я думаю. Спасибо за информацию! - person Stefan; 18.05.2010
comment
пожалуйста! :) теперь, когда вы его проверяете, не могли бы вы рассказать, как вы собираетесь информировать пользователя об ошибке проверки? В настоящее время я ищу лучшие методы для того же. - person Niks; 19.05.2010
comment
Нихил Патил, я просто использую Toast, чтобы сообщить пользователю, что он сделал что-то не так. Есть ли какая-то причина, по которой это не будет эффективно в вашем случае? - person Yevgeny Simkin; 19.11.2010
comment
Конечно, Toast — это естественный способ на Android. Но когда у нас есть значительное количество элементов на экране, которые нуждаются в проверке, тосты кажутся неправильным выбором (ИМХО, это будет раздражать пользователя). Я экспериментировал с TextView.setError() (developer.android.com/reference/android/widget/ - person Niks; 22.11.2010
comment
Хотя у TextWatcher плохая поддержка, он работает... вроде! - person Tivie; 22.11.2010
comment
Что делать, если вы хотите заменить EditText значением по умолчанию при неудачной проверке? Изменение внутри одной из этих функций приведет к ее повторному запуску или, что еще хуже, навсегда, если само значение по умолчанию недействительно. Я прав в этом мышлении? - person theblang; 06.02.2014
comment
@mattblang Я думаю, что afterTextChanged срабатывает только в том случае, если взаимодействие с пользователем меняет текст. Так что программная настройка не должна создавать проблем. Но это всего лишь предположение. Попробуйте и дайте нам знать? - person Niks; 06.02.2014
comment
@NikhilPatil java.lang.StackOverflowError - person theblang; 06.02.2014
comment
@mattblang Так что ты прав! Было бы очень плохой идеей использовать это, если вы также хотите установить значение по умолчанию. - person Niks; 07.02.2014

TextWatcher, на мой вкус, немного многословен, поэтому я сделал кое-что более простым для восприятия:

public abstract class TextValidator implements TextWatcher {
    private final TextView textView;

    public TextValidator(TextView textView) {
        this.textView = textView;
    }

    public abstract void validate(TextView textView, String text);

    @Override
    final public void afterTextChanged(Editable s) {
        String text = textView.getText().toString();
        validate(textView, text);
    }

    @Override
    final public void beforeTextChanged(CharSequence s, int start, int count, int after) { /* Don't care */ }

    @Override
    final public void onTextChanged(CharSequence s, int start, int before, int count) { /* Don't care */ }
}

Просто используйте это так:

editText.addTextChangedListener(new TextValidator(editText) {
    @Override public void validate(TextView textView, String text) {
       /* Validation code here */
    }
});
person Christopher Perry    schedule 07.08.2012
comment
+1 Этот абстрагированный способ намного лучше, чем использовать его как есть! :) - person Niks; 30.10.2012
comment
Раз уж мы говорим о валидации, вы, наверное, имеете в виду EditText? - person Sergo Pasoevi; 17.02.2014
comment
@fremmedehenvendelser : каждый EditText IS-A TextView - person Niks; 28.05.2014
comment
удивительная абстракция и использование абстрактного класса - person Saher Ahwal; 13.09.2014
comment
Мне нравится это решение. Но когда я пытаюсь реализовать его, я получаю эту ошибку: Вызвано: java.lang.NullPointerException: попытка вызвать виртуальный метод «void android.widget.EditText.addTextChangedListener (android.text.TextWatcher)» для нулевой ссылки на объект - person fullmeriffic; 09.04.2015
comment
@fullmeriffic, скорее всего, вы не инициализировали свой EditText. Убедитесь, что вы вызываете addTextChangedListener после разрешения вашего edittext из представления - person Ghostli; 14.05.2015
comment
Как вы можете сделать новый TextValidator(), если это абстрактный класс? - person Stephane; 20.08.2015
comment
@StephaneEybert Это анонимный класс - person Christopher Perry; 20.08.2015
comment
Библиотека ButterKnife может быть интересна всем, кто хочет писать более короткий код. - person black; 01.03.2016
comment
Принцип разделения интерфейсов на практике - person Maciej Beimcik; 19.02.2018
comment
Идеальное решение вышеуказанной проблемы. Отличная работа. Помогли решить мне мою проблему. - person Juzer Taher; 10.04.2021

Если вам нужны красивые всплывающие окна и изображения проверки при возникновении ошибки, вы можете использовать setError метод класса EditText, как я описываю здесь

Скриншот использования setError, сделанный Донном Фелкером, автором связанного поста

person Donn Felker    schedule 23.11.2011
comment
Как заставить TextWatcher получить доступ к двум EditText? Я успешно добавил TextWatcher в свой passwordConfirmTextField, но мне нужно сослаться на другие passwordTextField, чтобы я мог их сравнить. Какие-либо предложения? - person Zonker.in.Geneva; 20.04.2020

Чтобы уменьшить многословность логики проверки, я создал библиотеку для Android. Он выполняет большую часть повседневных проверок с использованием аннотаций и встроенных правил. Существуют такие ограничения, как @TextRule, @NumberRule, @Required, @Regex, @Email, @IpAddress, @Password и т. д.,

Вы можете добавить эти аннотации к своим ссылкам на виджеты пользовательского интерфейса и выполнить проверки. Это также позволяет вам выполнять проверки асинхронно, что идеально подходит для таких ситуаций, как проверка уникального имени пользователя с удаленного сервера.

На главной странице проекта есть пример использования аннотаций. Вы также можете прочитать сопутствующую запись в блоге где я написал примеры кода о том, как писать собственные правила для проверки.

Вот простой пример, иллюстрирующий использование библиотеки.

@Required(order = 1)
@Email(order = 2)
private EditText emailEditText;

@Password(order = 3)
@TextRule(order = 4, minLength = 6, message = "Enter at least 6 characters.")
private EditText passwordEditText;

@ConfirmPassword(order = 5)
private EditText confirmPasswordEditText;

@Checked(order = 6, message = "You must agree to the terms.")
private CheckBox iAgreeCheckBox;

Библиотека расширяемая, вы можете написать свои правила, расширив класс Rule.

person Ragunath Jawahar    schedule 23.10.2012
comment
Эта библиотека работает как шарм. Но аннотации @TextRule были удалены из версии 2.0.3? - person LTroya; 08.04.2016
comment
Он был заменен аннотацией @Length. - person Ragunath Jawahar; 08.04.2016
comment
@RagunathJawahar Я заметил, что проверка не работает, если вы проверяете входящие данные, т.е. contact , поэтому я пытаюсь проверить электронную почту, которая пришла из Intent -> Contacts , но как только я сосредоточусь на EditText и добавлю/удалю любой текст, тогда проверка работает, поскольку проверка также вызывается для TextChange, а validate() также вызывается, когда мы получать данные от Контакта. - person Ronak Mehta; 25.10.2016

Это было хорошее решение от здесь

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++) { 
            String checkMe = String.valueOf(source.charAt(i));

            Pattern pattern = Pattern.compile("[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz123456789_]*");
            Matcher matcher = pattern.matcher(checkMe);
            boolean valid = matcher.matches();
            if(!valid){
                Log.d("", "invalid");
                return "";
            }
        } 
        return null; 
    } 
};

edit.setFilters(new InputFilter[]{filter}); 
person Daniel Magnusson    schedule 14.08.2012
comment
как использовать его вместе с пробелом и не ограничивать два пробела рядом друг с другом? - person chiru; 16.04.2014

Обновленный подход - TextInputLayout:

Google недавно запустил библиотеку поддержки дизайна, и есть один компонент под названием TextInputLayout и поддерживает отображение ошибки через setErrorEnabled(boolean) и setError(CharSequence).

Как им пользоваться?

Шаг 1: Оберните EditText с помощью TextInputLayout:

  <android.support.design.widget.TextInputLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:id="@+id/layoutUserName">

    <EditText
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:hint="hint"
      android:id="@+id/editText1" />

  </android.support.design.widget.TextInputLayout>

Шаг 2. Подтвердите ввод

// validating input on a button click
public void btnValidateInputClick(View view) {

    final TextInputLayout layoutUserName = (TextInputLayout) findViewById(R.id.layoutUserName);
    String strUsername = layoutLastName.getEditText().getText().toString();

    if(!TextUtils.isEmpty(strLastName)) {
        Snackbar.make(view, strUsername, Snackbar.LENGTH_SHORT).show();
        layoutUserName.setErrorEnabled(false);
    } else {
        layoutUserName.setError("Input required");
        layoutUserName.setErrorEnabled(true);
    }
}

Я создал пример в моем репозитории Github. !

person Paresh Mayani    schedule 25.07.2015
comment
Лучший ответ, но мне пришлось использовать com.google.android.material.textfield.TextInputLayout (обратите внимание на изменение материала). Получил это из этого ответа: stackoverflow.com/a/56753953/900394 - person Alaa M.; 08.07.2020

Я написал класс, расширяющий EditText, который изначально поддерживает некоторые методы проверки и на самом деле очень гибкий.

Текущие, как я пишу, изначально поддерживаются с помощью методов проверки атрибутов XML:

  1. альфа
  2. буквенно-цифровой
  3. числовой
  4. общее регулярное выражение
  5. пустая строка

Вы можете проверить это здесь

Надеюсь, тебе понравится :)

person Andrea Baccega    schedule 24.05.2012

Я считаю, что InputFilter больше подходит для проверки ввода текста на Android.

Вот простой пример: Как использовать InputFilter для ограничения количества символов в EditText в Android?

Вы можете добавить Toast, чтобы сообщить пользователю о ваших ограничениях. Также проверьте тег android: inputType.

person Moisés    schedule 05.10.2011
comment
Это хорошее решение для вещей, которые можно проверять по мере ввода (буквенно-цифровой ввод), но оно не будет работать для вещей, которые должны проверяться только после того, как пользователь закончит ввод (адрес электронной почты). - person Peter Ajtai; 13.12.2011
comment
Как бы вы вызвали этот тост? Фильтр предотвращает реакцию любых текстовых наблюдателей... Возможно, с помощью onKeyListener? - person span; 23.08.2012
comment
Я активировал этот Toast с условием IF из метода filter() (в классе InputFilter). - person Moisés; 20.09.2012

Мне нужно было выполнить проверку внутри поля, а не проверку между полями, чтобы проверить, что мои значения были значениями с плавающей запятой без знака в одном случае и значениями с плавающей запятой со знаком в другом. Вот что, кажется, работает для меня:

    <EditText
        android:id="@+id/x" 
        android:background="@android:drawable/editbox_background" 
        android:gravity="right" 
        android:inputType="numberSigned|numberDecimal" 
    />

Обратите внимание: внутри "numberSigned|numberDecimal" не должно быть пробелов. Например: «numberSigned | numberDecimal» не будет работать. Я не уверен, почему.

person user405821    schedule 01.01.2011

Это выглядит очень многообещающе и именно то, что мне заказал доктор:

валидатор EditText

    public void onClickNext(View v) {
    FormEditText[] allFields    = { etFirstname, etLastname, etAddress, etZipcode, etCity };
    
    
    boolean allValid = true;
    for (FormEditText field: allFields) {
        allValid = field.testValidity() && allValid;
    }
    
    if (allValid) {
        // YAY
    } else {
        // EditText are going to appear with an exclamation mark and an explicative message.
    }
}

пользовательские валидаторы плюс встроенные:

  • regexp: для пользовательского регулярного выражения.
  • numeric: только числовое поле.
  • альфа: только для альфа-поля.
  • алфавитно-цифровой: угадайте, что?
  • personName: проверяет, является ли введенный текст именем или фамилией человека.
  • personFullName: проверяет, является ли введенное значение полным полным именем.
  • электронная почта: проверяет, является ли поле действительным адресом электронной почты.
  • creditCard: проверяет, содержит ли поле действительную кредитную карту, используя алгоритм Луна.
  • телефон: проверяет, содержит ли поле действительный номер телефона.
  • имя_домена: проверяет, содержит ли поле допустимое имя домена (всегда проходит проверку на уровне API ‹ 8).
  • ipAddress: проверяет, содержит ли поле допустимый IP-адрес.
  • webUrl: проверяет, содержит ли поле действительный URL-адрес (всегда проходит проверку на уровне API ‹ 8).
  • дата: проверяет, является ли поле допустимым форматом даты/даты и времени (если установлен customFormat, проверяется с помощью customFormat )
  • nocheck: ничего не проверяется, кроме пустого поля.
person Abs    schedule 18.12.2013

В файле main.xml

Вы можете поместить следующий атрибут, чтобы подтвердить, что только алфавитный символ может быть принят в тексте редактирования.

Сделай это :

  android:entries="abcdefghijklmnopqrstuvwxyz"
person KKumar    schedule 07.04.2014

Вы можете получить желаемое поведение, слушая, когда пользователь нажимает кнопку «Готово» на клавиатуре, а также ознакомьтесь с другими советами по работе с EditText в моем посте "Проверка формы Android — правильный путь"

Образец кода:

mTextView.setOnEditorActionListener(new TextView.OnEditorActionListener() {
    @Override
    public boolean onEditorAction(TextView view, int actionId, KeyEvent event) {
        if (actionId == EditorInfo.IME_ACTION_DONE) {                    
            validateAndSubmit();
            return true;
        }
        return false;
    }});  
person zasadnyy    schedule 04.08.2013

для проверки электронной почты и пароля попробуйте

  if (isValidEmail(et_regemail.getText().toString())&&etpass1.getText().toString().length()>7){
      if (validatePassword(etpass1.getText().toString())) {
      Toast.makeText(getApplicationContext(),"Go Ahead".....
      }
      else{

       Toast.makeText(getApplicationContext(),"InvalidPassword".....
       }

}else{

 Toast.makeText(getApplicationContext(),"Invalid Email".....
}


public boolean validatePassword(final String password){
    Pattern pattern;
    Matcher matcher;
    final String PASSWORD_PATTERN = "^(?=.*[0-9])(?=.*[A-Z])(?=.* 
    [@#$%^&+=!])(?=\\S+$).{4,}$";
    pattern = Pattern.compile(PASSWORD_PATTERN);
    matcher = pattern.matcher(password);

    return matcher.matches();
}

public final static boolean isValidEmail(CharSequence target) {
    if (target == null)
        return false;

    return android.util.Patterns.EMAIL_ADDRESS.matcher(target).matches();
}
person Syed Danish Haider    schedule 10.05.2018

Я создал эту библиотеку для Android, где вы можете легко проверить материальный дизайн EditText внутри и EditTextLayout следующим образом:

    compile 'com.github.TeleClinic:SmartEditText:0.1.0'

то вы можете использовать его следующим образом:

<com.teleclinic.kabdo.smartmaterialedittext.CustomViews.SmartEditText
    android:id="@+id/passwordSmartEditText"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:setLabel="Password"
    app:setMandatoryErrorMsg="Mandatory field"
    app:setPasswordField="true"
    app:setRegexErrorMsg="Weak password"
    app:setRegexType="MEDIUM_PASSWORD_VALIDATION" />

<com.teleclinic.kabdo.smartmaterialedittext.CustomViews.SmartEditText
    android:id="@+id/ageSmartEditText"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:setLabel="Age"
    app:setMandatoryErrorMsg="Mandatory field"
    app:setRegexErrorMsg="Is that really your age :D?"
    app:setRegexString=".*\\d.*" />

Затем вы можете проверить, действительно ли это так:

    ageSmartEditText.check()

Дополнительные примеры и настройки можно найти в репозитории https://github.com/TeleClinic/SmartEditText.

person Karim    schedule 22.12.2017