如何对多个 EditText 使用单个 TextWatcher?

在我的视图布局中有三个 EditText小部件。有没有办法使用一个单一的 TextWatcher为所有三个 EditTexts

88958 次浏览
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) {
}
};

然后:

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

我刚遇到这个问题。我通过创建 TextWatcher的内部类实现来解决这个问题,该实现以 View 作为参数。然后,在方法实现中,只需打开视图,查看 Editable来自哪个视图

声明:

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

用法:

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

让您的类从 Activity 继承并实现 TextWatcher。

然后通过多态性的魔力,您只需要订阅事件。

这不会告诉您 TextEdit 改变了什么,但是结合使用 This 和 Sky Kelsey的答案,您可以很好地解决这个问题。

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

如果只想使用 after TextChanged 比较编辑器:

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

它将与这个代码一起工作

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


}
};

然后在 oncreate 中添加这个

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

MultiTextWatcher 实现

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

用法

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

我是这样做的:

创建一个 EditText 的 ArrayList,然后使用一个 for 循环为所有 EditText 应用 TextWatcher,如果对所有 EditText 都有一个行为,那么只需要在那里应用它,如果对某些特定 EditText 有特定的行为,那么可以使用一个 if 语句来选择并应用到各个 EditText。

这是我的代码:

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


}

希望这个能帮上忙

我知道这是个老问题了,我们做出了正确的决定。我会写自己的,也许会对某人有所帮助。

模拟经典示例,其中我们有 N 个 EditText,并且我们希望在所有字段都已填充的情况下显示按钮。这个例子是有意义的,特别是如果进一步使用验证器为每一个。

我做了一个关于这个问题的例子,但是你可以做任何设置

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


}
}


现在看起来很简单

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

我会添加一个布局,这样你就不会浪费时间

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

我知道这个问题很老了,但是我想分享我的一个解决方案(在 Kotlin)。我的解决方案是对@Shwarz Andrei 的答案的改进,我的理由是如果你想操纵更多的事物/对象。

不需要同时传递 list of EditTextsa Button作为参数,只需要传递 list of editText。然后在自定义类中实现一个 lambda,比如:

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

然后在 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
}
}
}

因此,每次调用 lambda 时,都会在某个 EditText 中发生更改

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

如果你想使用 OnTextChanged比较下面提到的 hashCode()-

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


}

或者

如果你想使用 更改后的文本比较下面提到的 Editable-

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

这是我对 Kotlin 的解决方案。您可以简单地使用引用相等(= = =)来检查同一个对象,它工作得很好。

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)

科特林密码:

设置文本监视器 //内部创建

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


为一般文本监视器设置功能 //外部创建

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


}
}