TextWatcher for more than one EditText

I want to implement the TextWatcher interface for more than one EditText fields. Currently I am using :

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

then overriding the methods in my Activity:

  • Force update android app when new version available
  • User settings saved in SharedPreferences removed or lost between reloads of app
  • Android: What is transport and jsonFactory in GoogleIdTokenVerifier.Builder?
  • “Back” button on Action bar - Android . How to go “back”?
  • Copy image to clipboard in android
  • How does su work on android? And what are the pre-requisites for it to work? What is rooting on Android?
  • 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 
    }
    

    However this is working fine but I’m looking for other ways so that I can explicitly identify that in which EditText field the SoftKeyboard is currently focused.

    Related posts:

    Move Android Eclipse project into workspace
    Using data-binding in android error: package *.*.databinding does not exist
    ImageView won't show image when set by setImageBitmap()
    Unit Test an Android Fragment
    Automatically removing unreferenced strings from strings.xml
    Including Google Play Services to Android Studio project
  • Best approach for oldschool 2D zelda-like game
  • Android: ScrollView force to bottom
  • Can I program for android using any JVM language?
  • Android/Crashlytics NoClassDefFoundError for com.crashlytics.android.beta.Beta at runtime
  • Webview to PDF ignores job name
  • Failed to resolve: com.android.support:appcompat-v7:26.0.0
  • 10 Solutions collect form web for “TextWatcher for more than one EditText”

    Suggested solution in @Sebastian Roth’s answer is not one instance of TextWatcher for some EditTexts. It is one class and n instances of that class for n EditTexts.

    Each EditText has its own Spannable. TextWatcher‘s events has this Spannable as s parameter. I check their hashCode (unique Id of each object). myEditText1.getText() returns that Spannable. So if the myEditText1.getText().hashCode() equals with s.hashCode() it means that s belongs to myEditText1

    So if you want to have one instance of TextWatcher for some EditTexts you should use this:

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

    and

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

    I would do it like this:

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

    using “CustomTextWatcher” idea, I done that

    1) Crated a new TextWatcherListener interface:

    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)Created and used EditTextExtended instead of EditText (in my case):

    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) So, where you need write this code:

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

    4)use them:

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

    Well, let me know what do you think.

    –EDIT–

    If you want to use only afterTextChanged compare editables:

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

    I use this solution:

    • Add method that returns listener:

      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) {
      
              }
          };
      }
      
    • Add listener to multiple EditText’s, you can also pass other parameters:

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

    One more way around is to add OnClickListener to EditText and set a global variable as given below

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

    Use this etCurrentEditor as a reference to currently edited EditText

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

    Yes, you could use multiple instances of a custom TextWatcher that store the TextView.
    (TextView is actually the class that has addTextChangedListener.)

    Similar to the hashCode solution above you can just check if getText()==s.
    Instead of either storing all your controls or findViewById multiple times, you could simply scan the content tree yourself once for the control that has the 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;
       }
    }
    

    Of course you could also use findTextView inside beforeTextChanged and onTextChanged.

    Global One class for all the activities.

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

    I implemented it as:

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

    and:

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

    You can always define TextWatcher as a parameter to addTextChangedListener method.This way you can have multiple definitions for each edit text.

    Android Babe is a Google Android Fan, All about Android Phones, Android Wear, Android Dev and Android Games Apps and so on.