TextWatcher für mehr als einen EditText


73

Ich möchte die TextWatcherSchnittstelle für mehr als ein EditTextFeld implementieren . Zur Zeit benutze ich:

text1.addTextChangedListener(this);
text2.addTextChangedListener(this);

Überschreiben Sie dann die Methoden in meiner Aktivität:

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) 
{
 // do some operation on text of text1 field
 // do some operation on text of text2 field 
}

Dies funktioniert zwar einwandfrei, aber ich suche nach anderen Möglichkeiten, damit ich explizit feststellen kann, auf welches EditTextGebiet sich das SoftKeyboardderzeit konzentriert.



1
@SkyKelsey Die Antwort, die Sie geschrieben haben, besteht darin, mehrere Instanzen von TextWatcher zu erstellen. Daher denke ich, dass dies nicht die perfekte Antwort auf die von OP gestellten Fragen ist. In Bezug auf meine Frage geht es darum, jeden EditText in einer TextWatcher-Schnittstellenmethode zu identifizieren.
Vikas Patidar

Antworten:


96

Die vorgeschlagene Lösung in der Antwort von @Sebastian Roth ist TextWatcherfür einige kein Beispiel EditTexts. Es ist eine Klasse und n Instanzen dieser Klasse für n EditTexts.

Jeder EditText hat seinen eigenen Spannable. TextWatcherDie Ereignisse von 'haben diesen Spannable als sParameter. Ich überprüfe ihren Hashcode (eindeutige ID jedes Objekts). myEditText1.getText () gibt diesen Spannable zurück. Also, wenn das myEditText1.getText().hashCode()gleich ist s.hashCode(), bedeutet das, dass zu sgehörtmyEditText1

Wenn Sie also TextWatcherfür einige eine Instanz haben möchten, EditTextssollten Sie Folgendes verwenden:

private TextWatcher generalTextWatcher = new TextWatcher() {    

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

        if (myEditText1.getText().hashCode() == s.hashCode())
        {
            myEditText1_onTextChanged(s, start, before, count);
        }
        else if (myEditText2.getText().hashCode() == s.hashCode())
        {
            myEditText2_onTextChanged(s, start, before, count);
        }
    }

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

        if (myEditText1.getText().hashCode() == s.hashCode())
        {
            myEditText1_beforeTextChanged(s, start, count, after);
        }
        else if (myEditText2.getText().hashCode() == s.hashCode())
        {
            myEditText2_beforeTextChanged(s, start, count, after);
        }
    }

    @Override
    public void afterTextChanged(Editable s) {
        if (myEditText1.getText().hashCode() == s.hashCode())
        {
            myEditText1_afterTextChanged(s);
        }
        else if (myEditText2.getText().hashCode() == s.hashCode())
        {
            myEditText2_afterTextChanged(s);
        }
    }

};

und

myEditText1.addTextChangedListener(generalTextWatcher);
myEditText2.addTextChangedListener(generalTextWatcher);

3
Haben Sie diese Lösung noch einmal überprüft? Was passiert, wenn ein Benutzer in beide Eingabefelder denselben Text eingibt?
Sebastian Roth

15
@SebastianRoth Jeder EditText hat seinen eigenen Spannable. TextWatcherEreignisse hat diese Spannable als CharSequenceoder EditableParameter. Ich überprüfe den Textwert von EditTexts nicht. Ich überprüfe ihren Hashcode (eindeutige ID jedes Objekts). myEditText1.getText()Gibt Spannablenicht den Textwert zurück. Also, wenn das myEditText1.getText().hashCode()gleich mit s.hashCode()bedeutet, dass s zu gehörtmyEditText1
Bobs

1
OK, danke für die Bearbeitung. Aber jetzt habe ich noch eine Frage. (Ich bin ziemlich neu in Android und Java, bitte nehmen Sie Kontakt mit mir auf.) Ich verstehe nicht, warum Sie die hashCode () -Methode verwenden, um zu testen, ob die spannbaren Objekte dieselben Objekte sind oder nicht. Warum nicht einfach mit "==" vergleichen? (In C # würde ich ObjectEquals () verwenden, aber in Java verwendet man nur ==, richtig?)
RenniePet

1
Dies ist eine schlechte Lösung. Sobald Sie zwei EditTexts mit derselben Zeichenfolge haben, schlägt dies fehl, da es sich um dieselbe Zeichenfolge (daher denselben Hashcode) im Speicher handelt.
Eurig Jones

1
Sind Sie sicher, dass alle Hashes einzigartig sind? Was ist mit Hash-Kollisionen?
miva2

87

Ich würde es so machen:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    EditText e = new EditText(this);
    e.addTextChangedListener(new CustomTextWatcher(e));
}

private class CustomTextWatcher implements TextWatcher {
    private EditText mEditText;

    public CustomTextWatcher(EditText e) { 
        mEditText = e;
    }

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

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

    public void afterTextChanged(Editable s) {
    }
}

6
Interessante Idee, aber dies bedeutet, dass Sie für jeden EditText einen eigenen Textbeobachter haben.
ArtOfWarfare

13
Diese Antwort ist nicht Single TextWatcher for multiple EditTexts. Es sind 3 Instanzen einer TextWatcher-Klasse. 3 separate TextWatcher steuern also 3 EditTexts.
Bobs

1
@breceivemail, eine Klasse, 3 Instanzen. Einverstanden ist es schwierig, wenn Leute ihren Objekttyp nicht angeben. Sein Ziel war es, den Code nur einmal zu schreiben, also ist er da.
SparK

Was ist daran so üblich? Ich verstehe es nicht
r3dm4n

@ Bobs, ich nehme an, es ist einfacher, 3 Objekte zu erstellen, als eines schwierig zu schreiben, und die zukünftigen Änderungen zu unterstützen.
CoolMind

13

Ich benutze diese Lösung:

  • Methode hinzufügen, die den Listener zurückgibt:

    private TextWatcher getTextWatcher(final EditText editText) {
        return 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) {
                // do what you want with your EditText
                editText.setText("blabla");
            }
    
            @Override
            public void afterTextChanged(Editable editable) {
    
            }
        };
    }
    
  • Fügen Sie Listener zu mehreren EditText's hinzu, Sie können auch andere Parameter übergeben:

    editText1.addTextChangedListener(getTextWatcher(editText1));
    editText2.addTextChangedListener(getTextWatcher(editText2));
    editText3.addTextChangedListener(getTextWatcher(editText3));
    

Beste aller Zeiten ans ... nichts am Code zu ändern.
Vielen

Einfach und daher die "beste Antwort"
Vibhav

Lief wie am Schnürchen.
Kunwar Shekhar Singh

12

Mit der Idee "CustomTextWatcher" habe ich das gemacht

1) Eine neue TextWatcherListener-Schnittstelle erstellt:

public interface TextWatcherExtendedListener extends NoCopySpan
{
    public void afterTextChanged(View v, Editable s);

    public void onTextChanged(View v, CharSequence s, int start, int before, int count);

    public void beforeTextChanged(View v, CharSequence s, int start, int count, int after);
}

2) Erstellt und verwendet EditTextExtended anstelle von EditText (in meinem Fall):

public class EditTextExtended extends EditText
{
   private TextWatcherExtendedListener  mListeners = null;

   public EditTextExtended(Context context) 
   {
     super(context);
   }

   public EditTextExtended(Context context, AttributeSet attrs)
   {
      super(context, attrs);
   }

   public EditTextExtended(Context context, AttributeSet attrs, int defStyle)
   {
        super(context, attrs, defStyle);
   }

   public void addTextChangedListener(TextWatcherExtendedListener watcher) 
   {    
       if (mListeners == null) 
       {
           mListeners = watcher;
       }
   }

   public void removeTextChangedListener(TextWatcherExtendedListener watcher) 
   {
       if (mListeners != null) 
       {
           mListeners = null;        
       }
   }

   void  sendBeforeTextChanged(CharSequence text, int start, int before, int after)
   {
       if (mListeners != null) 
       {
           mListeners.beforeTextChanged(this, text, start, before, after);
       }
   }

   void  sendOnTextChanged(CharSequence text, int start, int before,int after) 
   {
       if (mListeners != null) 
       {
           mListeners.onTextChanged(this, text, start, before, after);
       }
   }

   void  sendAfterTextChanged(Editable text) 
   {
       if (mListeners != null)
       {
           mListeners.afterTextChanged(this, text);
       }
   }
}

3) Also, wo Sie diesen Code schreiben müssen:

myEditTextExtended.addTextChangedListener(this) //Let implement TextWatcherExtendedListener methods

4) benutze sie:

@Override
public void onTextChanged(View v, CharSequence s, int start, int before, int count) 
{
   //Tested and works
   //do your stuff  
}


@Override
public void beforeTextChanged(View v, CharSequence s, int start, int count, int after)
{   
     //not yet tested but it should work    
}

@Override
public void afterTextChanged(View v, Editable s) 
{
    //not yet tested but it should work 
}

Lassen Sie mich wissen, was Sie denken.


Ich denke, dies ist der direkteste Ansatz für dieses Problem. +1
AustrianDude

12

--BEARBEITEN--

Wenn Sie nur afterTextChanged verwenden möchten, vergleichen Sie die bearbeitbaren Dateien:

@Override
public void afterTextChanged(Editable editable) {
    if (editable == mEditText1.getEditableText()) {
        // DO STH
    } else if (editable == mEditText2.getEditableText()) {
        // DO STH
    }
}

1
Geht dies nicht davon aus, dass in mehreren EditText-Ansichten niemals derselbe Text vorhanden sein wird? Abhängig von der App ist dies möglicherweise keine gültige Annahme.
RenniePet

Verdammt, es tut mir sehr leid, aber ich bin jetzt überzeugt, dass ich falsch lag. Ich denke jetzt, dass sowohl Ihre Originalversion als auch die bearbeitete Version korrekt sind - Sie vergleichen das von EditText.getEditableText () zurückgegebene Java-Objekt mit dem bereitgestellten Editable-Implementierungsobjekt, nicht mit den beteiligten Texten. (In meinen Tests scheinen die beiden Objekte immer ein SpannableStringBuilder-Objekt zu sein, und die Dokumentation von Google für SpannableStringBuilder.equals () besagt eindeutig, dass Objekte verglichen werden, nicht der enthaltene Text.)
RenniePet

@RenniePet Die erste Version meiner Antwort war falsch. Wir sollten die Werte der Bearbeitungstexte nicht vergleichen. Jetzt funktioniert es großartig. Ich sehe, dass meine Antwort irgendwo oben in diesem Thread sein sollte.
Tomasz

Aus irgendeinem Grund funktioniert dies in meinem Emulator, aber nicht auf dem realen Gerät. Schließlich hat diese Antwort für mich funktioniert : stackoverflow.com/a/13787221/2263329 Vergleichen hashCode()des Editable.
Mahmudul Hasan Shohag

2

Eine weitere Möglichkeit ist um hinzuzufügen , OnClickListenerzu EditTextund eine globale Variable gesetzt , wie unten angegeben

EditText etCurrentEditor;//Global variable

@Override
    public void onClick(View v) {
        // TODO Auto-generated method stub
        if(v instanceof EditText){
            etCurrentEditor=(EditText)v;
        }
    }

Verwenden Sie diesen etCurrentEditor als Referenz auf den aktuell bearbeiteten EditText

@Override
    public void afterTextChanged(Editable editable) {
        // TODO Auto-generated method stub
        switch (etCurrentEditor.getId()) {
        case R.id.EDITTEXTID:
            break;
        default:
            break;
        }
    }

2

Ich habe es implementiert als:

edittext1.addTextChangedListener(this);
edittext2.addTextChangedListener(this);
edittext3.addTextChangedListener(this);

und:

@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(edittext1.hasFocus()){
        //text changed for edittext1
    }else if(edittext2.hasFocus()){
        //text changed for edittext2
    }else {
        //text changed for edittext3
    }
}

@Override
public void afterTextChanged(Editable editable) {

}

2

Nachdem ich verschiedene Wege ausprobiert habe, um dies zu erreichen, finde ich den richtigen Weg, EditText.isFocused()um voneinander zu unterscheiden. Zum Beispiel:

    private class OnTextChangedListener implements 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) {

    }

    @Override
    public void afterTextChanged(Editable editable) {
        if (edtName.isFocused()) {
            //do something
        } else if (edtEmail.isFocused()) {
            //do something
        } else if (edtContent.isFocused()) {
             //do something
        }
    }
}

1

Ja, Sie können mehrere Instanzen eines benutzerdefinierten Benutzers verwenden TextWatcher, in denen das gespeichert ist TextView. ( TextViewIst eigentlich die Klasse, die hat addTextChangedListener.)

Ähnlich wie bei der obigen hashCode-Lösung können Sie nur überprüfen, ob getText()==s. Anstatt alle Ihre Steuerelemente zu speichern oder findViewByIdmehrmals, können Sie den Inhaltsbaum einfach einmal selbst nach dem Steuerelement durchsuchen, das über das Steuerelement verfügt CharSequence.

public TextView findTextView(View v, CharSequence s)
{
   TextView tv;
   ViewGroup vg;
   int i, n;

   if (v instanceof TextView)
   {
      tv = (TextView) v;
      if (tv.getText()==s) return(tv);
   }

   else if (v instanceof ViewGroup)
   {
      vg = (ViewGroup) v;
      n = vg.getChildCount();
      for(i=0;i<n;i++)
      {
         tv = findTextView(vg.getChildAt(i), s);
         if (tv!=null) return(tv);
      }
   }

   return(null);
}

public void afterTextChanged(Editable s)
{
   TextView tv=findTextView(findViewById(android.R.id.content), s);
   if (tv==null) return;
   switch(tv.getId())
   {
      case R.id.path:
         break;
      case  R.id.title:
         break;
   }
}

Natürlich können Sie auch findTextViewinnen beforeTextChangedund verwenden onTextChanged.


Wunderbare Lösung. Es kann den EditText identifizieren, den ich bearbeite, wenn er in überschriebenen TextWatcher-Methoden verwendet wird. Können Sie ein wenig erklären, wie Sie zu dieser Lösung gekommen sind und `findViewById (android.R.id.content) verwendet haben, um die Bearbeitungsansicht zu erhalten?
Randika Vishman

findViewById(android.R.id.content)ist ein bisschen übertrieben, es bringt dir das, ViewGroupwas deinen Inhalt enthält. Es ist besser, den niedrigsten Wert auszuwählen, ViewGroupder alle interessanten Informationen enthält, die den Text ändern.
Renate

1

Global Eine Klasse für alle Aktivitäten.

CustomTextWatcher.java

package org.logicbridge.freshclub.customizedItems;

import android.content.Context;
import android.text.Editable;
import android.text.TextWatcher;
    public class CustomTextWatcher implements TextWatcher {
        private EditText mEditText;
        Context context;

        public CustomTextWatcher(EditText e, Context context) {
            mEditText = e;
            this.context = context;
        }

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

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

        public void afterTextChanged(Editable s) {

        }
    }

1

Sie können dies tun, um die ID der Bearbeitungstexte abzurufen. Es ist nicht getestet, aber lassen Sie mich wissen, ob es funktioniert.

//setting textWatcher for the editText
textWatcher(owner_name);


public void textWatcher(final EditText editText){

    TextWatcher watcher = new TextWatcher() {
        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {

           if(editText.getId()==R.id.your_id){
             //Do something
           }   
        }

        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
          if(editText.getId()==R.id.your_id){
          //Do something
          }
        }

        @Override
        public void afterTextChanged(Editable s) { }
    };

    editText.addTextChangedListener(watcher);
}

0

Sie können jederzeit TextWatchereinen Parameter für die addTextChangedListenerMethode definieren. Auf diese Weise können Sie für jeden Bearbeitungstext mehrere Definitionen festlegen .


0

Vergleichen Sie einfach die Hash-Codes von edittext und string wie mit der hashCode () -Methode

@Override
public void afterTextChanged(Editable s) {

    if (editext.getText().hashCode() == s.hashCode()){
        type1Total(type1List);
    }

}

0

Das habe ich getan ...

private TextWatcher textWatcher = new TextWatcher() {
    @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 (editText1.getText().length() > 0
                && editText2.getText().length() > 0
                && editText3.getText().length() > 0) {

            button.setEnabled(true);
        } else {

            button.setEnabled(false);
        }

    }

    @Override
    public void afterTextChanged(Editable s) {

    }

Fügen Sie dann einfach den TextWatcher zu jedem EditText in der onCreate-Methode hinzu und behalten Sie hier standardmäßig die Schaltfläche setEnabled (false) bei.

button.setEnabled(false); 

    editText1.addTextChangedListener(textWatcher);
    editText2.addTextChangedListener(textWatcher);
    editText3.addTextChangedListener(textWatcher);

0

Wenn Sie Kotlin verwenden, erledigt die Erweiterungsfunktion die Aufgabe. Zum Beispiel müssen wir TextWatcher zu editText1und hinzufügeneditText2

Erstellen Sie eine Erweiterungsfunktion wie folgt:

 fun EditText.addTextWatcher() {
        this.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) {
                        // you do some common operations here

                        when (this@addTextWatcher) {
                            editText1 -> {
                                // do something for editText1
                            }
                            editText2 -> {
                                // do something for editText2
                            }
                        }
                    }
                }
        )
    }

Fügen Sie dann einfach den Textwatcher wie folgt zu EditTexts hinzu

editText1.addTextWatcher()
editText2.addTextWatcher()
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.