android sur Text Change Listener

265

J'ai une situation, où il y a deux domaines. field1et field2. Tout ce que je veux faire, c'est vider field2quand field1est changé et vice versa. Donc, à la fin, un seul champ contient du contenu.

field1 = (EditText)findViewById(R.id.field1);
field2 = (EditText)findViewById(R.id.field2);

field1.addTextChangedListener(new TextWatcher() {

   public void afterTextChanged(Editable s) {}

   public void beforeTextChanged(CharSequence s, int start,
     int count, int after) {
   }

   public void onTextChanged(CharSequence s, int start,
     int before, int count) {
      field2.setText("");
   }
  });

field2.addTextChangedListener(new TextWatcher() {

   public void afterTextChanged(Editable s) {}

   public void beforeTextChanged(CharSequence s, int start,
     int count, int after) {
   }

   public void onTextChanged(CharSequence s, int start,
     int before, int count) {
     field1.setText("");
   }
  });

Il fonctionne très bien si je joins addTextChangedListenerà field1seulement, mais quand je le fais pour les deux champs de l'application se bloque. Évidemment parce qu'ils essaient de se changer indéfiniment. Une fois les field1modifications effacées field2à ce moment, elles field2sont modifiées de sorte qu'elles s'effacent field1et ainsi de suite ...

Quelqu'un peut-il suggérer une solution?

inrob
la source
pour les nouveaux utilisateurs, optez pour la liaison de données bidirectionnelle en utilisant un champ de chaîne observable, car toute la solution fournie ici peut produire starting waiting blocking gc allocce type d'erreur, ce qui peut même entraîner un blocage et un blocage .. alors optez pour la liaison de données, c'est sûr et recommandé par google maintenant ..
Maifee Ul Asad

Réponses:

460

Vous pouvez ajouter une coche pour effacer uniquement lorsque le texte dans le champ n'est pas vide (c'est-à-dire lorsque la longueur est différente de 0).

field1.addTextChangedListener(new TextWatcher() {

   @Override
   public void afterTextChanged(Editable s) {}

   @Override    
   public void beforeTextChanged(CharSequence s, int start,
     int count, int after) {
   }

   @Override    
   public void onTextChanged(CharSequence s, int start,
     int before, int count) {
      if(s.length() != 0)
        field2.setText("");
   }
  });

field2.addTextChangedListener(new TextWatcher() {

   @Override
   public void afterTextChanged(Editable s) {}

   @Override
   public void beforeTextChanged(CharSequence s, int start,
     int count, int after) {
   }

   @Override
   public void onTextChanged(CharSequence s, int start,
     int before, int count) {
      if(s.length() != 0)
         field1.setText("");
   }
  });

Documentation TextWatcher ici .

Veuillez également respecter les conventions de dénomination .

user2336315
la source
1
comment détecter après tout changement de champ, car, il détecte chaque fois qu'il change, lorsqu'un bouton est enfoncé.
Rafael Guimarães
20

Je sais que c'est vieux, mais quelqu'un pourrait le retrouver un jour.

J'ai eu un problème similaire où j'appellerais setText sur un EditText et onTextChanged serait appelé lorsque je ne le voulais pas. Ma première solution a été d'écrire du code après avoir appelé setText () pour réparer les dommages causés par l'auditeur. Mais ce n'était pas très élégant. Après avoir fait des recherches et des tests, j'ai découvert que l'utilisation de getText (). Clear () efface le texte de la même manière que setText (""), mais comme il ne définit pas le texte, l'écouteur n'est pas appelé, de sorte que résolu mon problème. J'ai changé tous mes appels setText ("") en getText (). Clear () et je n'avais plus besoin des bandages, donc peut-être que cela résoudra votre problème aussi.

Essaye ça:

Field1 = (EditText)findViewById(R.id.field1);
Field2 = (EditText)findViewById(R.id.field2);

Field1.addTextChangedListener(new TextWatcher() {

   public void afterTextChanged(Editable s) {}

   public void beforeTextChanged(CharSequence s, int start,
     int count, int after) {
   }

   public void onTextChanged(CharSequence s, int start,
     int before, int count) {
      Field2.getText().clear();
   }
  });

Field2.addTextChangedListener(new TextWatcher() {

   public void afterTextChanged(Editable s) {}

   public void beforeTextChanged(CharSequence s, int start,
     int count, int after) {
   }

   public void onTextChanged(CharSequence s, int start,
     int before, int count) {
     Field1.getText().clear();
   }
  });
RTHarston
la source
11

Si vous utilisez Kotlin pour le développement Android, vous pouvez ajouter à l' TextChangedListener()aide de ce code:

myTextField.addTextChangedListener(object : TextWatcher{
        override fun afterTextChanged(s: Editable?) {}

        override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}

        override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
    })
iHulk
la source
5

Un peu en retard de réponse, mais voici une solution réutilisable:

/**
 * An extension of TextWatcher which stops further callbacks being called as 
 * a result of a change happening within the callbacks themselves.
 */
public abstract class EditableTextWatcher implements TextWatcher {

    private boolean editing;

    @Override
    public final void beforeTextChanged(CharSequence s, int start, 
                                                    int count, int after) {
        if (editing)
            return;

        editing = true;
        try {
            beforeTextChange(s, start, count, after);
        } finally {
            editing = false;
        }
    }

    protected abstract void beforeTextChange(CharSequence s, int start, 
                                                     int count, int after);

    @Override
    public final void onTextChanged(CharSequence s, int start, 
                                                int before, int count) {
        if (editing)
            return;

        editing = true;
        try {
            onTextChange(s, start, before, count);
        } finally {
            editing = false;
        }
    }

    protected abstract void onTextChange(CharSequence s, int start, 
                                            int before, int count);

    @Override
    public final void afterTextChanged(Editable s) {
        if (editing)
            return;

        editing = true;
        try {
            afterTextChange(s);
        } finally {
            editing = false;
        }
    }

    public boolean isEditing() {
        return editing;
    }

    protected abstract void afterTextChange(Editable s);
}

Ainsi, lorsque ce qui précède est utilisé, tous les setText()appels qui se produisent dans TextWatcher n'entraîneront pas à nouveau l'appel de TextWatcher:

/**
 * A setText() call in any of the callbacks below will not result in TextWatcher being 
 * called again.
 */
public class MyTextWatcher extends EditableTextWatcher {

    @Override
    protected void beforeTextChange(CharSequence s, int start, int count, int after) {
    }

    @Override
    protected void onTextChange(CharSequence s, int start, int before, int count) {
    }

    @Override
    protected void afterTextChange(Editable s) {
    }
}
Eurig Jones
la source
5

J'ai également rencontré le même problème stackOverflowet je continue d'obtenir des exceptions, et je viens avec la solution suivante.

edt_amnt_sent.addTextChangedListener(new TextWatcher() {    
    @Override
    public void afterTextChanged(Editable s) {
        if (skipOnChange)
            return;

        skipOnChange = true;
        try {
            //method
        } catch (NumberFormatException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            skipOnChange = false;
        }
    }
});

edt_amnt_receive.addTextChangedListener(new TextWatcher() {

    @Override
    public void afterTextChanged(Editable s) {

        if (skipOnChange)
            return;

        skipOnChange = true;
        try {
            //method
        } catch (NumberFormatException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            skipOnChange = false;
        }
    }
});

déclaré initialement booléen skipOnChange = false;

Sumit
la source
1
"stack full" Je pense que vous voulez dire Stack Overflow;)
A Droid
4

Vous pouvez également utiliser la méthode hasFocus ():

public void onTextChanged(CharSequence s, int start,
     int before, int count) {
     if (Field2.hasfocus()){
         Field1.setText("");
     }
   }

Testé pour une mission universitaire sur laquelle je travaillais pour convertir des échelles de température lorsque l'utilisateur les tapait. Fonctionne parfaitement et c'est beaucoup plus simple.

renommer
la source
1
Qu'en est-il de editText.setText lorsque l'utilisateur y entre? EditText a le focus dans ce cas
Evgenii Vorobei
meilleure solution .
Syed Hissaan
3

vérifiez String avant d'en définir un autre EditTextsur vide. si Field1est vide, alors pourquoi changer à nouveau en ("")? afin que vous puissiez vérifier la taille de votre chaîne avec s.lenght () ou toute autre solution

une autre façon de vérifier la longueur de String est:

String sUsername = Field1.getText().toString();
if (!sUsername.matches(""))
{
// do your job
}
Shayan Pourvatan
la source
2

J'ai écrit ma propre extension pour cela, très utile pour moi. (Kotlin)

Vous ne pouvez écrire que comme ça:

editText.customAfterTextChanged { editable -> 
    //You have accessed the editable object. 
}

Mon extension:

fun EditText.customAfterTextChanged(action: (Editable?)-> Unit){
    this.addTextChangedListener(object : TextWatcher {
       override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}
       override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}
       override fun afterTextChanged(editable: Editable?) {
        action(editable)
    }
})}
Burak Dizlek
la source
2
editText.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {

            }
            @Override
            public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
                if (noteid != -1) {
                    MainActivity.notes.set(noteid, String.valueOf(charSequence));
                    MainActivity.arrayAdapter.notifyDataSetChanged();
                }
            }
            @Override
            public void afterTextChanged(Editable editable) {

            }
        });

dans ce code noteid est essentiellement des arguments repris qui sont mis dans le retrait ou passés à travers le retrait.

  Intent intent = getIntent();
         noteid = intent.getIntExtra("noteid", -1);

le code à la baisse est essentiellement le code supplémentaire, si vous voulez comprendre plus clairement.

how to make the menu or insert the menu in our code , 
    create the  menu folder this the folder created by going into the raw
    ->rightclick->
    directory->name the folder as you wish->
    then click on the directory formed->
    then click on new file and then name for file as you wish ie the folder name file
    and now type the 2 lines code in it and see the magic.

nouveau code d'activité nommé NoteEditor.java à des fins d'édition, mon application est simplement l'application de note.

package com.example.elavi.notes;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.widget.EditText;
import android.widget.Toast;

import static android.media.CamcorderProfile.get;
public class NoteEditorActivity extends AppCompatActivity {
    EditText editText;
    int noteid;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_note_editor);
        editText = findViewById(R.id.editText);
        Intent intent = getIntent();
         noteid = intent.getIntExtra("noteid", -1);
        if (noteid != -1) {
            String text = MainActivity.notes.get(noteid);
            editText.setText(text);

           Toast.makeText(getApplicationContext(),"The arraylist content is"+MainActivity.notes.get(noteid),Toast.LENGTH_SHORT).show();
        }
        else
        {
            Toast.makeText(getApplicationContext(),"Here we go",Toast.LENGTH_SHORT).show();
            MainActivity.notes.add("");
            noteid=MainActivity.notes.size()-1;
        }
        editText.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {

            }
            @Override
            public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
                if (noteid != -1) {
                    MainActivity.notes.set(noteid, String.valueOf(charSequence));
                    MainActivity.arrayAdapter.notifyDataSetChanged();
                }
            }
            @Override
            public void afterTextChanged(Editable editable) {

            }
        });
    }
}
Garish somptueux
la source
1

Dans Kotlin, utilisez simplement la fonction d' extension KTX : (Il utilise TextWatcher)

yourEditText.doOnTextChanged { text, start, count, after -> 
        // action which will be invoked when the text is changing
    }


importer core-KTX:

implementation "androidx.core:core-ktx:1.2.0"
Francis
la source
1

Nous pouvons supprimer le TextWatcher pour un champ juste avant de modifier son texte, puis le rajouter après avoir modifié le texte.

Déclarez Text Watchers pour field1 et field2 en tant que variables distinctes pour leur donner un nom: par exemple pour field1

private TextWatcher Field_1_Watcher = new TextWatcher() {
    @Override
    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
    }

    @Override
    public void afterTextChanged(Editable s) {
    }

    @Override
    public void onTextChanged(CharSequence s, int start, int before, int count) {

    }

};

puis ajoutez l'observateur en utilisant son nom: field1.addTextChangedListener(Field_1_Watcher)pour champ1 , et field2.addTextChangedListener(Field_2_Watcher)pour champ2

Avant de modifier le texte field2, supprimez le TextWatcher: field2.removeTextChangedListener(Field_2_Watcher) changez le texte: field2.setText("")

puis ajoutez le TextWatcher: field2.addTextChangedListener(Field_2_Watcher)

Faites de même pour l'autre domaine

Keith Kiarie
la source
-3

Ajouter un arrière-plan dynamiquement dans la onCreateméthode:

getWindow().setBackgroundDrawableResource(R.drawable.background);

supprimez également l'arrière-plan de XML.

Ankit Kumar
la source