Android: Comment puis-je valider l'entrée EditText?

169

J'ai besoin de faire la validation d'entrée de formulaire sur une série de EditTexts. J'utilise OnFocusChangeListeners pour déclencher la validation après que l'utilisateur a tapé dans chacun d'eux, mais cela ne se comporte pas comme souhaité pour le dernier EditText.

Si je clique sur le bouton "Terminé" en tapant dans le EditText final, alors le InputMethod est déconnecté, mais techniquement le focus n'est jamais perdu sur le EditText (et donc la validation ne se produit jamais).

Quelle est la meilleure solution?

Dois-je surveiller le moment où InputMethod se dissocie de chaque EditText plutôt que lorsque le focus change? Si c'est le cas, comment?

Stefan
la source
1
Avez-vous vraiment besoin de valider l'entrée EditText en même temps que l'utilisateur tape? Pourquoi ne validez-vous pas simplement le EditText une fois que l'utilisateur a cliqué sur le bouton Terminé?
Cristian
C'est exactement ce que je veux: que le texte soit vérifié lorsque l'utilisateur clique sur le bouton Terminé (par bouton Terminé, je veux dire le bouton "Terminé" sur le QWERTY InputManager ... PAS le bouton d'envoi du formulaire). Sauf que lorsque j'appuie sur le bouton Terminé, le focus reste sur le dernier élément du formulaire, et ma méthode de validation n'est jamais déclenchée. J'espère que ma formulation est claire ...
Stefan
La solution de @Cristian est exactement ce que je recherchais et se trouve ici: stackoverflow.com/questions/43013812/…
LampPost
@Cristian Arrive un peu en retard, mais je cherche une solution où les EditText sont validés pendant que la personne tape. J'ai un formulaire de connexion / inscription et je souhaite afficher le bouton «Soumettre» uniquement lorsque les données du formulaire sont valides.
Zonker.in.Genève

Réponses:

154

Pourquoi n'utilisez-vous pas TextWatcher?

Puisque vous avez un certain nombre de EditTextcases à valider, je pense que les suivantes vous conviendront:

  1. Votre activité implémente l' android.text.TextWatcherinterface
  2. Vous ajoutez des écouteurs TextChanged à vos boîtes EditText
txt1.addTextChangedListener(this);
txt2.addTextChangedListener(this);
txt3.addTextChangedListener(this);
  1. Parmi les méthodes remplacées, vous pouvez utiliser la afterTextChanged(Editable s)méthode comme suit
@Override
public void afterTextChanged(Editable s) {
    // validation code goes here
}

L' Editable saide n'aide pas vraiment à trouver le texte de la zone EditText qui est modifié. Mais vous pouvez directement vérifier le contenu des cases EditText comme

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

dans la même méthode. J'espère que je suis clair et si je le suis, ça aide! :)

EDIT: Pour une approche plus propre, reportez-vous à la réponse de Christopher Perry ci-dessous.

Niks
la source
3
Cela ressemble exactement à ce dont j'ai besoin. Je n'avais pas entendu parler de TextWatcher (nouveau dans le SDK / API), mais je vais le tester et voir s'il se comporte comme je le pense. Merci pour l'info!
Stefan
1
de rien! :) maintenant que vous le validez, pourriez-vous nous dire comment allez-vous informer l'utilisateur de l'échec de la validation? Je recherche actuellement les meilleures méthodes pour la même chose.
Niks
Nikhil Patil, j'utilise juste Toast pour informer l'utilisateur qu'il a fait quelque chose de mal. Y a-t-il une raison pour laquelle cela ne sera pas efficace dans votre cas?
Yevgeny Simkin
5
Bien sûr, Toast est un moyen naturel sur Android. Mais lorsque nous avons une quantité considérable d'éléments à l'écran qui doivent être validés, les toasts ne semblent pas être le bon choix (à mon humble avis, cela ennuierait l'utilisateur) J'ai expérimenté TextView.setError () ( developer.android.com / reference / android / widget /…
Niks
1
Bien que le support de TextWatcher soit médiocre, cela fonctionne ... un peu!
Tivie
126

TextWatcher est un peu verbeux à mon goût, j'ai donc rendu quelque chose d'un peu plus facile à avaler:

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

Utilisez-le simplement comme ceci:

editText.addTextChangedListener(new TextValidator(editText) {
    @Override public void validate(TextView textView, String text) {
       /* Validation code here */
    }
});
Christopher Perry
la source
4
@fremmedehenvendelser: chaque EditTextIS-ATextView
Niks
2
abstraction impressionnante et utilisation de la classe abstraite
Saher Ahwal
1
@fullmeriffic vous n'avez probablement pas initialisé votre EditText. Assurez-vous d'appeler addTextChangedListeneraprès avoir résolu votre edittext à partir de la vue
Ghostli
1
@StephaneEybert C'est une classe anonyme
Christopher Perry
2
Principe de ségrégation d'interface en pratique
Maciej Beimcik
92

Si vous voulez de jolis popups et images de validation lorsqu'une erreur se produit, vous pouvez utiliser la setErrorméthode de la EditTextclasse comme je la décris ici

Capture d'écran de l'utilisation de setError prise de Donn Felker, l'auteur de l'article lié

Donn Felker
la source
Comment obtenir un TextWatcher pour accéder à deux EditTexts? J'ai ajouté avec succès un TextWatcher à mon passwordConfirmTextField, mais je dois faire référence à l'autre passwordTextField, afin de pouvoir les comparer. Aucune suggestion?
Zonker.in.Genève
26

Afin de réduire la verbosité de la logique de validation, j'ai créé une bibliothèque pour Android . Il prend en charge la plupart des validations quotidiennes à l'aide d'annotations et de règles intégrées. Il existe des contraintes telles que @TextRule, @NumberRule, @Required, @Regex, @Email, @IpAddress, @Password, etc.,

Vous pouvez ajouter ces annotations à vos références de widget d'interface utilisateur et effectuer des validations. Il vous permet également d'effectuer des validations de manière asynchrone, ce qui est idéal pour des situations telles que la vérification d'un nom d'utilisateur unique à partir d'un serveur distant.

Il existe un exemple sur la page d'accueil du projet sur la façon d'utiliser les annotations. Vous pouvez également lire l' article de blog associé dans lequel j'ai écrit des exemples de codes sur la façon d'écrire des règles personnalisées pour les validations.

Voici un exemple simple qui décrit l'utilisation de la bibliothèque.

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

La bibliothèque est extensible, vous pouvez écrire vos propres règles en étendant la Ruleclasse.

Ragunath Jawahar
la source
Cette bibliothèque fonctionne comme un charme. Mais les annotations @TextRule ont été supprimées de la version 2.0.3?
LTroya
1
Il a été remplacé par l' @Lengthannotation.
Ragunath Jawahar
@RagunathJawahar J'ai noté que la validation ne fonctionne pas si vous validez les données entrantes, c'est-à-dire le contact, donc j'essaie de valider l'e-mail qui vient de Intent -> Contacts, mais une fois que je me concentre sur EditText et ajoute / supprime du texte, puis validation fonctionne car la validation est également appelée sur TextChange et validate () est également appelée lorsque nous recevons des données de Contact.
Ronak Mehta
11

C'était une bonne solution d' ici

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}); 
Daniel Magnusson
la source
Comment puis-je l'utiliser avec l'espace et ne pas limiter deux espaces l'un à côté de l'autre?
chiru
10

Approche mise à jour - TextInputLayout:

Google a récemment lancé une bibliothèque de support de conception et il existe un composant appelé TextInputLayout et il prend en charge l'affichage d'une erreur via setErrorEnabled(boolean)et setError(CharSequence).

Comment l'utiliser?

Étape 1: Enveloppez votre EditText avec 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>

Étape 2: valider l'entrée

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

J'ai créé un exemple sur mon référentiel Github , consultez l'exemple si vous le souhaitez!

Paresh Mayani
la source
Meilleure réponse, mais j'ai dû utiliser com.google.android.material.textfield.TextInputLayout(notez le changement matériel ). Je l'ai
Alaa M.
8

J'ai écrit une classe qui étend EditText qui prend en charge nativement certaines méthodes de validation et est en fait très flexible.

Au moment où j'écris, les méthodes de validation d' attributs xml prises en charge nativement sont les suivantes:

  1. alpha
  2. alphanumérique
  3. numérique
  4. expression régulière générique
  5. vide de chaîne

Vous pouvez le vérifier ici

Je espère que vous l'apprécierez :)

Andrea Baccega
la source
7

Je trouve que InputFilter est plus approprié pour valider les entrées de texte sur Android.

Voici un exemple simple: Comment utiliser InputFilter pour limiter les caractères dans un EditText sous Android?

Vous pouvez ajouter un toast pour informer l'utilisateur de vos restrictions. Vérifiez également la balise android: inputType.

Moisés
la source
1
C'est une bonne solution pour les choses qui peuvent être validées au fur et à mesure que vous tapez (entrée alphanumérique), mais cela ne fonctionnerait pas pour les choses qui ne devraient être validées qu'une fois que l'utilisateur a fini de saisir l'entrée (adresse e-mail).
Peter Ajtai
Comment déclencheriez-vous ce toast? Le filtre empêche les observateurs de texte de réagir ... Peut-être avec un onKeyListener?
span
J'ai déclenché ce Toast avec une condition IF de la méthode filter () (dans la classe InputFilter).
Moisés
6

J'avais besoin de faire une validation intra-champ et non une validation inter-champ pour tester que mes valeurs étaient des valeurs à virgule flottante non signées dans un cas et des valeurs à virgule flottante signées dans un autre. Voici ce qui semble fonctionner pour moi:

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

Notez que vous ne devez pas avoir d'espaces à l'intérieur de "numberSigned | numberDecimal". Par exemple: "numberSigned | numberDecimal" ne fonctionnera pas. Je ne sais pas pourquoi.

user405821
la source
5

Cela semble vraiment prometteur et exactement ce que le doc m'a commandé:

EditText Validator

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

validateurs personnalisés plus ceux intégrés:

  • regexp : pour une expression régulière personnalisée
  • numérique : pour un champ uniquement numérique
  • alpha : pour un champ alpha uniquement
  • alphaNumeric : devinez quoi?
  • personName : vérifie si le texte saisi est le prénom ou le nom d'une personne.
  • personFullName : vérifie si la valeur saisie est un nom complet complet.
  • email : vérifie que le champ est un email valide
  • creditCard : vérifie que le champ contient une carte de crédit valide à l'aide de l' algorithme de Luhn
  • phone : vérifie que le champ contient un numéro de téléphone valide
  • domainName : vérifie que le champ contient un nom de domaine valide (passe toujours le test au niveau d'API <8)
  • ipAddress : vérifie que le champ contient une adresse IP valide
  • webUrl : vérifie que le champ contient une URL valide (passe toujours le test au niveau d'API <8)
  • date : vérifie que le champ est un format date / date / heure valide (si customFormat est défini, vérifie avec customFormat)
  • nocheck : Il ne vérifie rien sauf le vide du champ.
Abdos
la source
2

Dans le fichier main.xml

Vous pouvez mettre l'attrubute suivant pour valider que seul le caractère alphabétique peut accepter dans edittext.

Faites ceci:

  android:entries="abcdefghijklmnopqrstuvwxyz"
KKumar
la source
2

Vous pouvez obtenir le comportement souhaité en écoutant lorsque l'utilisateur clique sur le bouton "Terminé" du clavier, consultez également d'autres conseils sur l'utilisation de EditText dans mon message "Validation du formulaire Android - la bonne manière"

Exemple de code:

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;
    }});  
zasadnyy
la source
0

pour la validation de l'email et du mot de passe, essayez

  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();
}
Syed Danois Haider
la source
-2

J'ai créé cette bibliothèque pour Android où vous pouvez valider une conception matérielle EditText à l'intérieur et EditTextLayout facilement comme ceci:

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

alors vous pouvez l'utiliser comme ceci:

<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.*" />

Ensuite, vous pouvez vérifier s'il est valide comme ceci:

    ageSmartEditText.check()

Pour plus d'exemples et de personnalisation, consultez le référentiel https://github.com/TeleClinic/SmartEditText

Karim
la source