Android sul listener del cambio di testo


265

Ho una situazione in cui ci sono due campi. field1e field2. Tutto quello che voglio fare è vuoto field2quando field1viene cambiato e viceversa. Quindi alla fine solo un campo ha dei contenuti.

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("");
   }
  });

Funziona bene se io attribuisco addTextChangedListenera field1solo, ma quando lo faccio per entrambi i campi l'applicazione si blocca. Ovviamente perché provano a cambiarsi indefinitamente. Una volta che field1cambia si cancella field2in questo momento field2è cambiato in modo che si cancella field1e così via ...

Qualcuno può suggerire qualche soluzione?


per i nuovi utenti, scegli l'associazione dati bidirezionale utilizzando un campo di stringhe osservabile, perché tutta la soluzione fornita qui può produrre starting waiting blocking gc allocquesto tipo di errore, che può anche portare a crash e blocco .. quindi scegli l'associazione dati, che è sicuro e raccomandato da google ora ..
Maifee Ul Asad

Risposte:


460

È possibile aggiungere un segno di spunta per cancellare solo quando il testo nel campo non è vuoto (ovvero quando la lunghezza è diversa da 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("");
   }
  });

Documentazione per TextWatcher qui .

Inoltre, si prega di rispettare le convenzioni di denominazione .


1
come rilevare dopo che tutti i campi sono cambiati, perché rileva ogni volta che cambia, quando viene premuto un pulsante qualsiasi.
Rafael Guimarães,

20

So che è vecchio ma qualcuno potrebbe imbattersi di nuovo un giorno.

Ho avuto un problema simile in cui avrei chiamato setText su un EditText e onTextChanged sarebbe stato chiamato quando non lo volevo. La mia prima soluzione è stata scrivere del codice dopo aver chiamato setText () per annullare il danno fatto dall'ascoltatore. Ma non era molto elegante. Dopo aver fatto qualche ricerca e test ho scoperto che usando getText (). Clear () cancella il testo più o meno allo stesso modo di setText (""), ma poiché non sta impostando il testo non viene chiamato l'ascoltatore, in modo che risolto il mio problema Ho cambiato tutte le mie chiamate setText ("") per getText (). Clear () e non avevo più bisogno delle bende, quindi forse anche questo risolverà il tuo problema.

Prova questo:

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

11

Se stai usando Kotlin per lo sviluppo Android, puoi aggiungere TextChangedListener()usando questo codice:

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) {}
    })

5

Un po 'in ritardo di una risposta, ma ecco una soluzione riutilizzabile:

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

Pertanto, quando si utilizza quanto sopra, tutte le setText()chiamate in corso all'interno di TextWatcher non comporteranno la richiamata di 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) {
    }
}

5

Ho anche affrontato lo stesso problema e continuo a ricevere stackOverfloweccezioni, e vengo con la seguente soluzione.

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

dichiarato inizialmente booleano skipOnChange = false;


1
"stack full" Penso che intendi Stack Overflow;)
A Droid

4

Puoi anche usare il metodo hasFocus ():

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

Ho provato questo per un incarico universitario a cui stavo lavorando per convertire le scale di temperatura quando l'utente le ha digitate. Ha funzionato perfettamente ed è molto più semplice.


1
Che dire di editText.setText quando l'utente inserisce in esso? EditText si concentra in questo caso
Evgenii Vorobei,

soluzione migliore .
Syed Hissaan,

3

controlla String prima di impostarne un altro EditTextsu vuoto. se Field1è vuoto, allora perché è necessario cambiare di nuovo in ("")? così puoi controllare la dimensione della tua stringa con s.lenght () o qualsiasi altra soluzione

un altro modo per verificare la lunghezza di String è:

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

2

Ho scritto la mia estensione per questo, molto utile per me. (Kotlin)

Puoi scrivere solo così:

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

La mia estensione:

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

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) {

            }
        });

in questo codice noteid è sostanzialmente argomenti ripresi che vengono inseriti nel rientro o passati attraverso il rientro.

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

il codice al rovescio della medaglia è fondamentalmente il codice extra, se vuoi capire più chiaramente.

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.

nuovo codice attività denominato NoteEditor.java a scopo di modifica, la mia app è di base l'app nota.

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) {

            }
        });
    }
}

1

In Kotlin usa semplicemente la funzione di estensione KTX : (Usa TextWatcher)

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


importazione core-KTX:

implementation "androidx.core:core-ktx:1.2.0"

1

È possibile rimuovere TextWatcher per un campo appena prima di modificarne il testo, quindi aggiungerlo nuovamente dopo aver modificato il testo.

Dichiara Watcher di testo sia per field1 che field2 come variabili separate per dare loro un nome: ad es. Per 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) {

    }

};

quindi aggiungi il watcher usando il suo nome: field1.addTextChangedListener(Field_1_Watcher)per field1 e field2.addTextChangedListener(Field_2_Watcher)per field2

Prima di modificare il testo field2 rimuovere TextWatcher: field2.removeTextChangedListener(Field_2_Watcher) modificare il testo: field2.setText("")

quindi aggiungere nuovamente TextWatcher: field2.addTextChangedListener(Field_2_Watcher)

Fai lo stesso per l'altro campo


-3

Aggiungi lo sfondo in modo dinamico nel onCreatemetodo:

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

rimuovere anche lo sfondo da XML.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.