Android auf Text Change Listener

265

Ich habe eine Situation, in der es zwei Felder gibt. field1und field2. Ich möchte nur leer sein, field2wenn field1es geändert wird und umgekehrt. Am Ende enthält also nur ein Feld Inhalt.

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

Es funktioniert gut , wenn ich anhängen addTextChangedListenerzu field1nur, aber wenn ich es für beide Felder die App abstürzt. Offensichtlich, weil sie versuchen, sich auf unbestimmte Zeit zu verändern. Sobald field1Änderungen, die field2in diesem Moment gelöscht werden, field2geändert werden, wird sie gelöscht field1und so weiter ...

Kann jemand eine Lösung vorschlagen?

inrob
quelle
Für neue Benutzer gilt die bidirektionale Datenbindung mithilfe eines beobachtbaren Zeichenfolgenfelds. Alle hier bereitgestellten Lösungen können starting waiting blocking gc allocdiese Art von Fehler verursachen, der sogar zum Absturz und zum Hängen führen kann sicher und jetzt von google empfohlen ..
Maifee Ul Asad

Antworten:

460

Sie können ein Häkchen hinzufügen, um nur zu löschen, wenn der Text im Feld nicht leer ist (dh wenn die Länge von 0 abweicht).

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

Dokumentation für TextWatcher hier .

Bitte beachten Sie auch die Namenskonventionen .

user2336315
quelle
1
wie man erkennt, nachdem sich alle Felder geändert haben, weil es jedes Mal erkennt, wenn es sich ändert, wenn eine Taste gedrückt wird.
Rafael Guimarães
20

Ich weiß, dass dies alt ist, aber eines Tages könnte jemand wieder darauf stoßen.

Ich hatte ein ähnliches Problem, bei dem ich setText für einen EditText aufrief und onTextChanged aufgerufen wurde, wenn ich es nicht wollte. Meine erste Lösung bestand darin, nach dem Aufruf von setText () Code zu schreiben, um den vom Listener verursachten Schaden rückgängig zu machen. Das war aber nicht sehr elegant. Nach einigen Recherchen und Tests stellte ich fest, dass mit getText (). Clear () der Text auf die gleiche Weise wie mit setText ("") gelöscht wird, aber da der Text nicht festgelegt wird, wird der Listener nicht aufgerufen löste mein Problem. Ich habe alle meine setText ("") - Aufrufe auf getText (). Clear () umgestellt und brauchte die Bandagen nicht mehr. Vielleicht löst das auch Ihr Problem.

Versuche dies:

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
quelle
11

Wenn Sie Kotlin für die Android-Entwicklung verwenden, können Sie Folgendes hinzufügen TextChangedListener():

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
quelle
5

Eine etwas späte Antwort, aber hier ist eine wiederverwendbare Lösung:

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

Wenn also das oben setText()Gesagte verwendet wird, führen Aufrufe im TextWatcher nicht dazu, dass der TextWatcher erneut aufgerufen wird:

/**
 * 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
quelle
5

Ich habe auch das gleiche Problem und bekomme immer wieder stackOverflowAusnahmen, und ich komme mit der folgenden Lösung.

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

anfangs deklariert boolean skipOnChange = false;

Sumit
quelle
1
"Stapel voll" Ich denke du meinst Stapelüberlauf;)
Ein Droide
4

Sie können auch die Methode hasFocus () verwenden:

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

Ich habe dies für eine College-Aufgabe getestet, an der ich gearbeitet habe, um Temperaturskalen während der Eingabe durch den Benutzer zu konvertieren. Hat perfekt funktioniert und ist viel einfacher.

Renam
quelle
1
Was ist mit editText.setText, wenn Benutzer darin eingeben? EditText hat Fokus in diesem Fall
Evgenii Vorobei
beste Lösung .
Syed Hissaan
3

Überprüfen Sie den String, bevor Sie einen anderen EditTextauf leer setzen. Wenn Field1es leer ist, warum muss es dann wieder auf ("") geändert werden? So können Sie die Größe Ihres Strings mit s.lenght () oder einer anderen Lösung überprüfen

Eine andere Möglichkeit, die Länge von String zu überprüfen, ist:

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

Ich habe meine eigene Erweiterung dafür geschrieben, sehr hilfreich für mich. (Kotlin)

Sie können nur so schreiben:

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

Meine Erweiterung:

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
quelle
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 diesem Code sind noteid im Grunde genommen Argumente, die zurückgenommen werden und in den Einzug eingefügt oder durch den Einzug geleitet werden.

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

Der Code auf der Unterseite ist im Grunde der zusätzliche Code, wenn Sie klarer verstehen wollen.

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.

neuer Aktivitätscode mit dem Namen NoteEditor.java zu Bearbeitungszwecken. Meine App ist im Grunde die Notiz-App.

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

            }
        });
    }
}
Verschwenderischer Garg
quelle
1

Verwenden Sie in Kotlin einfach die KTX-Erweiterungsfunktion : (Es wird verwendet TextWatcher)

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


Import core-KTX:

implementation "androidx.core:core-ktx:1.2.0"
Francis
quelle
1

Wir können den TextWatcher für ein Feld unmittelbar vor der Bearbeitung des Texts entfernen und ihn nach der Bearbeitung des Textes wieder hinzufügen.

Deklarieren Sie Text Watchers für Feld1 und Feld2 als separate Variablen, um ihnen einen Namen zu geben: z. B. für Feld1

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

    }

};

Fügen Sie dann den Watcher mit seinem Namen hinzu: field1.addTextChangedListener(Field_1_Watcher)für Feld1 und field2.addTextChangedListener(Field_2_Watcher)für Feld2

Entfernen Sie vor dem Ändern des Feld2- Textes den TextWatcher: field2.removeTextChangedListener(Field_2_Watcher) Ändern Sie den Text: field2.setText("")

Fügen Sie dann den TextWatcher wieder hinzu: field2.addTextChangedListener(Field_2_Watcher)

Machen Sie dasselbe für das andere Feld

Keith Kiarie
quelle
-3

Fügen Sie Hintergrund dynamisch in onCreateMethode hinzu:

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

Entfernen Sie auch den Hintergrund aus XML.

Ankit Kumar
quelle