web-dev-qa-db-fra.com

Détecter si le contenu de EditText a été modifié par l'utilisateur ou par programme?

J'aurais besoin d'un moyen pour détecter si le EditText a été modifié par l'utilisateur en tapant quelque chose ou par l'application en changeant le texte par programme. Une façon standard de le faire? Je suppose que je pourrais toujours faire quelque chose de piraté comme désinstaller le TextWatcher avant setText() et le remettre à nouveau après, mais il doit y avoir une meilleure façon de le faire ... non?

J'ai essayé de vérifier si le EditText est focalisé dans le TextWatcher, mais cela n'a pas été très utile car le EditTexts est de toute façon focalisé "semi-aléatoirement" lors du défilement ...

Contexte

J'ai un ListView avec EditTexts dans chaque listitem. J'ai résolu le problème de base du stockage des valeurs des EditTexts pour les réutiliser lorsque l'utilisateur fait défiler.

J'ai également un TextWatcher qui résume les valeurs de tous les EditTexts et affiche la somme lorsque l'utilisateur modifie le contenu de l'un des EditTexts.

Le problème est que lorsque je fais défiler la liste et que mon adaptateur personnalisé ressaisit les valeurs stockées dans les EditTexts sur bindView(), cela déclenche également la méthode TextWatchers afterTextChanged(), provoquant le défilement vers décalage car la fonction de sommation est déclenchée.

47
Magnus W

Cela s'est réglé il y a longtemps, mais pour tous ceux qui trouvent leur chemin ici à la recherche d'une réponse, voici ce que j'ai fait:

J'ai fini par définir la balise de EditText sur une valeur arbitraire juste avant de la modifier par programme, de modifier la valeur, puis de réinitialiser la balise sur null. Ensuite, dans ma méthode TextWatcher.afterTextChanged (), je vérifie si la balise est nulle ou non pour déterminer si c'est l'utilisateur ou le programme qui a changé la valeur. Fonctionne comme un charme!

Quelque chose comme ça:

edit.setTag( "arbitrary value" );
edit.setText( "My Text Value" );
edit.setTag(null);

puis

public void afterTextChanged(Editable s) {
    if( view.getTag() == null )             
        // Value changed by user
    else
        // Value changed by program
}
48
Magnus W

La réponse acceptée est parfaitement valable, mais j'ai une autre approche;

@Override
public void onTextChanged(CharSequence charSequence, 
                         int start, int before, int count) {
    boolean userChange = Math.abs(count - before) == 1; 
    if (userChange) { 

    }
}

Cela fonctionne en vérifiant si le changement était un seul caractère. Ce n'est pas une solution à toute épreuve car les opérations de copier-coller peuvent être manquées et les modifications non-utilisateur d'un seul caractère seront également manquées. Selon votre cas d'utilisation, cela pourrait être une solution viable.

7
Petrus

Une chose qui m'a aidé est d'avoir le champ booléen canListenInput. Utilisez-le à l'intérieur de l'observateur.

    email.addTextChangedListener(new TextWatcher() {
        @Override
        public void afterTextChanged(Editable s) {
            if (canListenInput) {
                emailChanged = true;
            }
        }
    });

Effacez-le avant de modifier le texte par programme. Placez-le à l'intérieur de onAttachedToWindow, (après l'état) de la restauration:

@Override
public void onAttachedToWindow() {
    super.onAttachedToWindow();
    canListenInput = true;
}
1
konmik