TextWatcher for more than one EditText

AndroidInterfaceAndroid ActivityAndroid EdittextTextwatcher

Android Problem Overview


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:

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.

Android Solutions


Solution 1 - Android

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

Solution 2 - Android

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

Solution 3 - Android

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

Solution 4 - Android

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.

Solution 5 - Android

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

Solution 6 - Android

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

Solution 7 - Android

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

Solution 8 - Android

After try several ways to achieve this, i find the right way using EditText.isFocused() to distinguish one to another. For example:

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

Solution 9 - Android

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.

Solution 10 - Android

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

Solution 11 - Android

You can do this for getting the id of the edit texts. It's not tested but let me know if it works.

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

Solution 12 - Android

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

Solution 13 - Android

just compare hash codes of the edittext and string like by using hashCode() method

@Override
public void afterTextChanged(Editable s) {

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

Solution 14 - Android

This is what I have done...

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

    }

Then just added the TextWatcher to each EditText in the onCreate method & also kept the button setEnabled(false) by default here.

button.setEnabled(false); 

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

Solution 15 - Android

If you are using Kotlin, extension function will do the job. For example, we need to add TextWatcher to editText1 and editText2

Create a extension function like this,

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

Then just add the textwatcher to EditTexts like this

editText1.addTextWatcher()
editText2.addTextWatcher()

Solution 16 - Android

I've done something like this to have only one TextWatcher class to control as many EditText either from Activity OR Fragment

You need to first create a MultiTextWatcher class as below

class MultiTextWatcher {

    private var callback: TextWatcherWithInstance? = null

    fun setCallback(callback: TextWatcherWithInstance): MultiTextWatcher {
        this.callback = callback
        return this
    }


    fun registerEditText(editText: EditText): MultiTextWatcher {
        editText.addTextChangedListener(object : TextWatcher {
            override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
                callback!!.beforeTextChanged(editText, s, start, count, after)
            }

            override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
                callback!!.onTextChanged(editText, s, start, before, count)
            }

            override fun afterTextChanged(editable: Editable) {
                callback!!.afterTextChanged(editText, editable)
            }
        })

        return this
    }

     interface TextWatcherWithInstance {
        fun beforeTextChanged(editText: EditText, s: CharSequence, start: Int, count: Int, after: Int)

        fun onTextChanged(editText: EditText, s: CharSequence, start: Int, before: Int, count: Int)

        fun afterTextChanged(editText: EditText, editable: Editable)
    }
}

Then in your Activity or Fragment, you need to register as many EditText as you want like below, and also I've used Data Binding to get references of the XML views and you can use your ways.

 private fun setTextWatchers() {
        MultiTextWatcher()
            .registerEditText(binding.etCompanyAddress)
            .registerEditText(binding.etCompanyIntro)
            .registerEditText(binding.etCompanyName)
            .registerEditText(binding.etCompanyPhone)
            .setCallback(object : MultiTextWatcher.TextWatcherWithInstance {
                override fun beforeTextChanged(editText: EditText, s: CharSequence, start: Int, count: Int, after: Int) {
                }

                override fun onTextChanged(editText: EditText, s: CharSequence, start: Int, before: Int, count: Int) {
                    when (editText) {
                        binding.etCompanyAddress -> {
                            //do your logic here
                        }
                        binding.etCompanyPhone -> {
                            //do your logic here and so on
                        }
                    }
                }

                override fun afterTextChanged(editText: EditText, editable: Editable) {

                }
            })
    }

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionVikas PatidarView Question on Stackoverflow
Solution 1 - AndroidBobsView Answer on Stackoverflow
Solution 2 - AndroidSebastian RothView Answer on Stackoverflow
Solution 3 - AndroidWojtekView Answer on Stackoverflow
Solution 4 - Androiduser3132789View Answer on Stackoverflow
Solution 5 - AndroidTomaszView Answer on Stackoverflow
Solution 6 - AndroidDeepak Samuel RajanView Answer on Stackoverflow
Solution 7 - AndroidLakhan SharmaView Answer on Stackoverflow
Solution 8 - AndroidHien Quang LeView Answer on Stackoverflow
Solution 9 - AndroidRenateView Answer on Stackoverflow
Solution 10 - AndroidDharmikView Answer on Stackoverflow
Solution 11 - AndroidOhhhThatVarunView Answer on Stackoverflow
Solution 12 - AndroidwwwView Answer on Stackoverflow
Solution 13 - Androidsaigopi.meView Answer on Stackoverflow
Solution 14 - Androiduser6897800View Answer on Stackoverflow
Solution 15 - AndroidveeyikpongView Answer on Stackoverflow
Solution 16 - AndroidSuraj BahadurView Answer on Stackoverflow