Reputation: 43349
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.
Upvotes: 75
Views: 79915
Reputation: 890
public class AddOnTextChangeListener implements TextWatcher {
public interface TextListener {
void onTextChanged(String value);
}
private final TextListener listener;
public AddOnTextChangeListener(TextListener listener) {
this.listener = listener;
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
listener.onTextChanged(s.toString());
}
@Override
public void afterTextChanged(Editable s) {
}
}
using :
editText.addTextChangedListener(new AddOnTextChangeListener(value -> {
}));
Upvotes: 0
Reputation: 3928
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) {
}
})
}
Upvotes: 0
Reputation: 857
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()
Upvotes: 0
Reputation: 4321
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);
}
Upvotes: 1
Reputation: 1
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);
Upvotes: 0
Reputation: 14908
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);
}
}
Upvotes: 0
Reputation: 158
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
}
}
}
Upvotes: 2
Reputation: 1348
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));
Upvotes: 15
Reputation: 1731
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) {
}
Upvotes: 3
Reputation: 1416
--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
}
}
Upvotes: 12
Reputation: 23000
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);
Upvotes: 97
Reputation: 1
You can always define TextWatcher
as a parameter to addTextChangedListener
method.This way you can have multiple definitions for each edit text.
Upvotes: 0
Reputation: 877
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;
}
}
Upvotes: 2
Reputation: 151
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.
Upvotes: 12
Reputation: 2345
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) {
}
}
Upvotes: 1
Reputation: 811
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
.
Upvotes: 1
Reputation: 11537
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) {
}
}
Upvotes: 89