How to use Single TextWatcher for multiple EditTexts?

AndroidTextwatcher

Android Problem Overview


I have three EditText widgets in my view layout. Is there a way to use a single TextWatcher for all three EditTexts?

Android Solutions


Solution 1 - Android

I just encountered this problem. I solved it by creating an inner class implementation of TextWatcher that takes a View as an argument. Then, in the method implementation, just switch on the view to see which one the Editable is coming from

Declaration:

private class GenericTextWatcher implements TextWatcher{

	private View view;
	private GenericTextWatcher(View view) {
		this.view = view;
	}

	public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {}
	public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {}

	public void afterTextChanged(Editable editable) {
		String text = editable.toString();
		switch(view.getId()){
			case R.id.name:
				model.setName(text);
				break;
			case R.id.email:
				model.setEmail(text);
				break;
			case R.id.phone:
				model.setPhone(text);
				break;
		}
	}
}

Usage:

name = (EditText) findViewById(R.id.name);
name.setText(model.getName());
name.addTextChangedListener(new GenericTextWatcher(name));

email = (EditText) findViewById(R.id.email);
email.setText(model.getEmail());
email.addTextChangedListener(new GenericTextWatcher(email));

phone = (EditText) findViewById(R.id.phone);
phone.setText(model.getPhone());
phone.addTextChangedListener(new GenericTextWatcher(phone));



Solution 2 - Android

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 3 - Android

It will work with this code

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

        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
            //YOUR CODE
        }

        @Override
        public void afterTextChanged(Editable s) {
          String outputedText = s.toString();

  mOutputText.setText(outputedText);
               
        }
    };

Then add this in oncreate

  mInputText.addTextChangedListener(watcher);
        e2.addTextChangedListener(watcher);
        e3.addTextChangedListener(watcher);
        e4.addTextChangedListener(watcher);
      

Solution 4 - Android

MultiTextWatcher Implementation

public class MultiTextWatcher {

    private TextWatcherWithInstance callback;

    public MultiTextWatcher setCallback(TextWatcherWithInstance callback) {
        this.callback = callback;
        return this;
    }

    public MultiTextWatcher registerEditText(final EditText editText) {
        editText.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
                callback.beforeTextChanged(editText, s, start, count, after);
            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
                callback.onTextChanged(editText, s, start, before, count);
            }

            @Override
            public void afterTextChanged(Editable editable) {
                callback.afterTextChanged(editText, editable);
            }
        });
        
        return this;
    }

    interface TextWatcherWithInstance {
        void beforeTextChanged(EditText editText, CharSequence s, int start, int count, int after);

        void onTextChanged(EditText editText, CharSequence s, int start, int before, int count);

        void afterTextChanged(EditText editText, Editable editable);
    }
}

Usage

    new MultiTextWatcher()
            .registerEditText(editText1)
            .registerEditText(editText2)
            .registerEditText(editText3)
            .setCallback(new TextWatcherWithInstance() {
                @Override
                public void beforeTextChanged(EditText editText, CharSequence s, int start, int count, int after) {
                    // TODO: Do some thing with editText
                }

                @Override
                public void onTextChanged(EditText editText, CharSequence s, int start, int before, int count) {
                    // TODO: Do some thing with editText
                }

                @Override
                public void afterTextChanged(EditText editText, Editable editable) {
                    // TODO: Do some thing with editText
                }
            });

Solution 5 - Android

If you want to use onTextChanged compare hashCode() mentioned below -

@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
    if(charSequence.hashCode() == first_edit_text.getText().hashCode()){
        // do other things 
    }

    if(charSequence.hashCode() == second_edit_text.getText().hashCode()){
       // do other things 
    }

}

Or

If you want to use afterTextChanged compare Editable mentioned below -

@Override
public void afterTextChanged(Editable editable) {
    if (editable == first_edit_text.getEditableText()) {
        // do other things 
    } else if (editable == second_edit_text.getEditableText()) {
       // do other things 
    }
}

Solution 6 - Android

This is my solution for kotlin. You can simply use Referential equality (===) to check same object and it's working perfectly.

val mTextWatcher = object : TextWatcher {
        override fun afterTextChanged(et: Editable?) {

            when {
                et === et1.editableText -> {
                    Toast.makeText(this@MainActivity, "EditText 1", Toast.LENGTH_LONG).show()
                }
                et === et2.editableText -> {
                    Toast.makeText(this@MainActivity, "EditText 2", Toast.LENGTH_LONG).show()
                }

            }
        }

        override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
        }
        override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
        }
    }
    et1.addTextChangedListener(mTextWatcher)
    et2.addTextChangedListener(mTextWatcher)

Solution 7 - Android

Have your class inherit from Activity and implement TextWatcher.

Then through the magic of polymorphism, you just need to subscribe to the events.

This won't tell you what TextEdit changed, however using a combination of this and Sky Kelsey's answer you could sort that out nicely.

public YourActivity extends Activity implements TextWatcher {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_YourActivity);

        //Subscribe to the events
        EditText txt1 = (EditText) findViewById(R.id.txt1);
        txt1.addTextChangedListener(this);
   
        EditText txt2 = (EditText) findViewById(R.id.txt2);
        txt2.addTextChangedListener(this);
	}
    	
        @Override
	public void onTextChanged(CharSequence s, int start, int before, int count) {

         	EditText txt1 = (EditText) findViewById(R.id.txt1);
        	EditText txt2 = (EditText) findViewById(R.id.txt2);
        	// You probably only want the text value from the EditText. But you get the idea. 
                doStuff(txt1,txt2);
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.calc, menu);
        return true;
	}

	@Override
	public void afterTextChanged(Editable s) {
        // TODO Auto-generated method stub
	}

	@Override
	public void beforeTextChanged(CharSequence s, int start, int count, int after) {
        // TODO Auto-generated method stub
	}
}

Solution 8 - Android

I know this is an old issue, and there is the right decision. I will write their own, maybe it will help someone.

Emulating the classic example where we have N EditText, and we want to show the button if all the fields are filled. This example makes sense, especially if further use validators for each one.

I made an example with respect to the issue, but you can do any set

MultiEditText.class

public class MultiEditText extends AppCompatActivity{

EditText ed_1, ed_2, ed_3;
Button btn_ok;

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.multi_edit_text);

    ed_1 = (EditText) findViewById(R.id.ed_1);
    ed_2 = (EditText) findViewById(R.id.ed_2);
    ed_3 = (EditText) findViewById(R.id.ed_3);
    btn_ok = (Button) findViewById(R.id.btn_ok);
    btn_ok.setEnabled(false);

    //if want more here can cycle interface List

     EditText[] edList = {ed_1, ed_2, ed_3};
     CustomTextWatcher textWatcher = new CustomTextWatcher(edList, btn_ok);
     for (EditText editText : edList) editText.addTextChangedListener(textWatcher);

    }
}

It looks very simple, now

CustomTextWatcher.class

public class CustomTextWatcher implements TextWatcher {

View v;
EditText[] edList;

public CustomTextWatcher(EditText[] edList, Button v) {
    this.v = v;
    this.edList = edList;
}

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

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

@Override
public void afterTextChanged(Editable s) {
    for (EditText editText : edList) {
        if (editText.getText().toString().trim().length() <= 0) {
            v.setEnabled(false);
            break;
        }
        else v.setEnabled(true);
    }
  }
}

I'll add a layout, so you do not waste time

multi_edit_text.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp">

<EditText
    android:id="@+id/ed_1"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_alignParentTop="true"
    android:layout_centerHorizontal="true"
    android:layout_marginTop="8dp" />

<EditText
    android:id="@+id/ed_2"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_below="@+id/ed_1"
    android:layout_centerHorizontal="true"
    android:layout_marginTop="8dp" />

<EditText
    android:id="@+id/ed_3"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_below="@+id/ed_2"
    android:layout_centerHorizontal="true"
    android:layout_marginTop="8dp" />

<Button
    android:id="@+id/btn_ok"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_below="@+id/ed_3"
    android:layout_centerHorizontal="true"
    android:layout_marginTop="8dp"
    android:text="OK" />
</RelativeLayout>

Solution 9 - Android

TextWatcher watcher = 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) {
    }

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

Then:

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

Solution 10 - Android

public class MainActivity extends AppCompatActivity{
	EditText value1, value2;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		//instantiate EditText controls
		value1 = (EditText)findViewById(R.id.txtValue1);
		value2 = (EditText)findViewById(R.id.txtValue2);
		
		//set up text changed listener
		value1.addTextChangedListener(new TextChange(value1));               
		value2.addTextChangedListener(new TextChange(value2));                       

	    //inner class
	    private class TextChange implements TextWatcher {
		
			 View view;
			 private TextChange (View v) {
				 view = v;
			 }

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

			 }

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

				 switch (view.getId()) {
					 case R.id.txtValue1:
						 //insert your TextChangedListener codes here
						 break;

					 case R.id.txtValue2:
						 //insert your TextChangedListener codes here
						 break;
				 }
			 }   
		 }
     }
}

Solution 11 - Android

For Kotlin Code:

set Text Watcher // inside on create

 etFirst.addTextChangedListener(generalTextWatcher)
 etFirstSecond.addTextChangedListener(generalTextWatcher)

make function for general text watcher // outside on create

 private val generalTextWatcher: TextWatcher = object : TextWatcher {
        override fun onTextChanged(
            s: CharSequence, start: Int, before: Int,
            count: Int
        ) {
            when (s.hashCode()) {
                etFirst.text.hashCode() -> { /* take value for first text */ }
                etSecond.text.hashCode() -> { /* take value for second text */ }
            }
        }

        override fun beforeTextChanged(
            s: CharSequence, start: Int, count: Int,
            after: Int
        ) {

        }

        override fun afterTextChanged(s: Editable) {

        }
    }

Solution 12 - Android

Here is how I did it:

Create an ArrayList of EditTexts, and then use a for loop to apply the TextWatcher for all EditTexts, if you have one behavior for all editTexts, then just apply it there, if you specific behaviors for some specific editTexts, then u can use an if statement to select and apply to individual editTexts.

Here is my code:

ArrayList<EditText> editTexts = new ArrayList<>(); // Container list

editText1 = (EditText) findViewById(R.id.editText1);
editText2 = (EditText) findViewById(R.id.editText2);
editText3 = (EditText) findViewById(R.id.editText3);

editTexts.add(editText1); // editTexts[0]
editTexts.add(editText2); // editTexts[1]
editTexts.add(editText3); // editTexts[2]

for (final EditText editText : editTexts) { //need to be final for custom behaviors 
    editText.addTextChangedListener(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) {

        }

        @Override
        public void afterTextChanged(Editable s) {
            //Apply general behavior for all editTexts

            if (editText == editTexts.get(1)) {
                //Apply custom behavior just for this editText                           
            }
        }
    });

}

Hope this helps

Solution 13 - Android

I know this question is old, however I wanted to share one of my solution (in Kotlin). My solution is an improvement of @Shwarz Andrei's answer, my reason was what if you wanted to manipulate more things/object.

Instead of passing both list of EditTexts and a Button as params, you'd only pass your list of editText. Then within you custom class you'd implement a lambda such:

var hasFilled:((Boolean)->Unit)? = null 

Then you will set or raise it inside the afterTextChanged

override fun afterTextChanged(p0: Editable?) {
       for (edit in _editTextList) {
           if (edit?.text.toString().trim().isEmpty()) {
                 hasFilled?.invoke(false) //<-- here 
               break
           } else {
               hasFilled?.invoke(true) //<--- here 
           }
       }
   }

>> So every time, there is a change in some EditText your lambda gets invoked

        val editTexts = listOf(emailEditText,passwordEditText) // your list of editText
        val textWatcher = customTextWatcher(editTexts) // initialize your custom object 
        editTexts.forEach { it -> it?.addTextChangedListener(textWatcher) } // each editText would listen for changes 


        textWatcher.hasFilled = { value ->  // now you have access to your lambda 
            if (value != true)  {
               // change the state of the button to unable 
              // do other things 
            } else {
              // change the state of the button to enable 
              // do other things 
            }
        }

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
QuestionbieView Question on Stackoverflow
Solution 1 - AndroidSky KelseyView Answer on Stackoverflow
Solution 2 - AndroidTomaszView Answer on Stackoverflow
Solution 3 - AndroidAsha BabuView Answer on Stackoverflow
Solution 4 - AndroidIlya GazmanView Answer on Stackoverflow
Solution 5 - AndroidAman JhamView Answer on Stackoverflow
Solution 6 - AndroidShohan Ahmed SijanView Answer on Stackoverflow
Solution 7 - AndroidNitroxDMView Answer on Stackoverflow
Solution 8 - AndroidShwarz AndreiView Answer on Stackoverflow
Solution 9 - AndroidCristianView Answer on Stackoverflow
Solution 10 - AndroidNg Kian KeongView Answer on Stackoverflow
Solution 11 - AndroidRahul KhatriView Answer on Stackoverflow
Solution 12 - AndroidSamiHajjajView Answer on Stackoverflow
Solution 13 - AndroidLamourView Answer on Stackoverflow