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

- 19,192
- 5
- 36
- 77

- 1,339
- 2
- 9
- 3
-
https://github.com/henrychuangtw/AutoInsertEditText – HenryChuang Jan 18 '17 at 02:10
13 Answers
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));

- 1,103
- 1
- 15
- 26

- 19,192
- 5
- 36
- 77
-
1Can you please tell what is 'model' in above code and where to declare it? – YuDroid Jun 25 '12 at 06:56
-
model is my own class that I am using to store the data entered by the user. It is just an example variable. Instead of model.setEmail(), you would use "text" in whatever way you see fit. – Sky Kelsey Jun 25 '12 at 22:29
-
Yes, I made it work for my application. But the problem is, my activity contains edittexts, which are all of kind to take input as a phone number and I need to set same kind of textwatcher for all. So its leading me to code redundancy. Do you hv any suggestion if I want to apply same kind of behaviour to multiple edittexts in which I have implemented OnTextChanged method for all of them?? – YuDroid Jun 26 '12 at 06:19
-
That's exactly what my example is doing :) You create one TextWatcher class, which saves a reference to an EditText. Then, for each EditText, you construct a new instance of that TextWatcher, and pass in a reference to the current EditText. – Sky Kelsey Jun 26 '12 at 22:42
-
42this answer is not `Single TextWatcher for multiple EditTexts`. It is 3 instances of one TextWatcher class. So 3 separate TextWatchers are controlling 3 EditTexts. – Bob Dec 08 '12 at 11:58
-
2Suggested solution is not one TextWatcher for some EditTexts. Check this answer: http://stackoverflow.com/a/13787221/779408 – Bob Dec 09 '12 at 12:07
-
2Works like a charm, combining this with a fragment containing form-elements to not lose data when changing aspect-orientation. – Mathijs Segers Feb 11 '15 at 15:05
-
1@breceivemail To be completely fair, "single TextWatcher" doesn't necessarily mean a single instance, could be a single class too. – Malcolm Apr 17 '16 at 22:14
-
Works like Gem! Very helpful to handle text-watching throughout the project. Thanks! – vss Mar 19 '19 at 09:36
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
}
}

- 1,406
- 1
- 18
- 28
-
11This will only work correctly if you use `==` instead of `.equals()`. – Jarett Millard Oct 17 '14 at 21:12
-
2You're genius! This is just comparing pointers not actual values stored on Editable! Yes! – Burak Tamtürk Dec 03 '14 at 15:51
-
5
-
-
1@Tomasz How does this work? Did you implement TextWatcher? Don't you have to override three methods if you do? – leonheess Oct 17 '18 at 14:55
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);

- 399
- 2
- 8
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
}
});

- 31,250
- 24
- 137
- 216
-
Why would you create another class to just chain them up?! I mean you still don't know which `TextView` the change is coming from. – Farid Jul 15 '20 at 15:15
-
nice solution. made some modifications and it is all set to go.. – other Tall guy May 17 '22 at 04:45
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
}
}

- 478
- 6
- 18
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)

- 4,391
- 1
- 33
- 39
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
}
}
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>

- 7,009
- 4
- 25
- 38

- 647
- 14
- 17
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;
}
}
}
}
}

- 990
- 1
- 16
- 25

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

- 198,401
- 62
- 356
- 264
-
2(Whining post warning) He probably has very similar validation code for all controls and doesn't want to copy and paste it 3 times :) I've hit it before, why can they send the control that generated the click on onClickListener and not on things like TextWatcher... The only workaround i can think of is make 3 TextWatchers that call the same procedure but with a pointer to their respective edit controls. – Torp Apr 18 '11 at 13:24
-
1@Torp, @bie: This answer might be of interest: http://stackoverflow.com/questions/4283062/textwatcher-for-more-than-one-edittext/4283532#4283532 Not sure it exactly solves the problem stated here, but, as shown, you could have the CustomTextWatcher automatically call another function which takes in the passed Editable. – Kevin Coppock Apr 18 '11 at 16:00
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) {
}
}

- 1,502
- 2
- 13
- 25
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

- 7,009
- 4
- 25
- 38

- 27
- 1
-
Thanks for the answer, but is this really the only way to do it? I mean it seems kind of complicated for something as common as a `onTextChanged` on an EditText. Adding an `onFocusChange` for multiple widgets is much simpler, because it passed the sender object with the method call. Then you can examine which object has triggered the call and handle it from there. – BdR Mar 27 '20 at 23:06
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
}
}

- 3,002
- 2
- 16
- 28