Je dois effectuer une validation de saisie de formulaire sur une série de EditTexts. J'utilise OnFocusChangeListeners pour déclencher la validation après que l'utilisateur a saisi chacun d'entre eux, mais cela ne se comporte pas comme souhaité pour le dernier EditText.
Si je clique sur le bouton "Terminé" lors de la saisie dans l'EditText final, alors la méthode InputMethod est déconnectée, mais techniquement, le focus n'est jamais perdu sur l'EditText (et la validation ne se produit donc jamais).
Quelle est la meilleure solution?
Devrais-je surveiller lorsque InputMethod se dissocie de chaque EditText plutôt que lorsque la focalisation change? Si c'est le cas, comment?
Pourquoi n'utilisez-vous pas TextWatcher
?
Étant donné que vous devez valider un certain nombre de EditText
boîtes, je pense que ce qui suit vous convient:
Android.text.TextWatcher
txt1.addTextChangedListener(this);
txt2.addTextChangedListener(this);
txt3.addTextChangedListener(this);
afterTextChanged(Editable s)
comme suit@Override
public void afterTextChanged(Editable s) {
// validation code goes here
}
Le Editable s
n'aide pas vraiment à trouver le texte de la zone de texte à modifier 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 à réponse de Christopher Perry ci-dessous.
TextWatcher est un peu prolixe à mon goût, alors j'ai 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 */ }
}
Il suffit de l'utiliser comme ceci:
editText.addTextChangedListener(new TextValidator(editText) {
@Override public void validate(TextView textView, String text) {
/* Validation code here */
}
});
Afin de réduire la verbosité de la logique de validation, j'ai créé un 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 widgets 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 du nom d'utilisateur unique d'un serveur distant.
Il y a un exemple sur le page d'accueil du projet sur l'utilisation des annotations. Vous pouvez également lire le article de blog associé où 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 classe Rule
.
C'était une bonne solution de 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});
Google a récemment lancé une bibliothèque de support à la conception. Il existe un composant appelé TextInputLayout . 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 la saisie
// 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!
Je trouve InputFilter plus approprié pour valider les entrées de texte sous 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 le tag Android: inputType.
J'ai écrit une classe qui étend EditText, qui supporte nativement certaines méthodes de validation et est en réalité très flexible.
Actuellement, au moment où j'écris, en mode natif pris en charge via les méthodes de validation des attributs xml sont :
Vous pouvez le vérifier ici
Je espère que vous l'apprécierez :)
J'avais besoin d'effectuer une validation intra-champ et non une validation inter-champ pour vérifier 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'espace dans "numberSigned | numberDecimal". Par exemple: "numberSigned | numberDecimal" ne fonctionnera pas. Je ne sais pas pourquoi.
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.
}
}
Dans le fichier main.xml
Vous pouvez mettre l'attribut suivant pour valider uniquement les caractères de l'alphabet pouvant être acceptés dans edittext.
Faire ceci:
Android:entries="abcdefghijklmnopqrstuvwxyz"
Vous pouvez obtenir le comportement souhaité en écoutant lorsque l'utilisateur appuie sur le bouton "Terminé" du clavier. Vous pouvez également consulter d'autres astuces sur l'utilisation d'EditText dans mon message "Validation de formulaire Android - de la bonne façon"
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;
}});
pour la validation de l'e-mail 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();
}