Андроид на прослушивателе изменения текста
У меня ситуация, когда есть два поля. field1
и field2
. Все что я хочу
do - пустой field2
при изменении field1
и наоборот. Так что в конце только
в одном поле есть содержимое.
field1 = (EditText)findViewById(R.id.field1);
field2 = (EditText)findViewById(R.id.field2);
field1.addTextChangedListener(new TextWatcher() {
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) {
field2.setText("");
}
});
field2.addTextChangedListener(new TextWatcher() {
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) {
field1.setText("");
}
});
Работает нормально, если я присоединяю addTextChangedListener
только к field1
, но когда
Я делаю это для обоих полей приложение вылетает. Очевидно, потому что они пытаются изменить
друг друга до бесконечности. Как только field1
изменяется, он очищает field2
в этот момент
field2
изменен, поэтому он очистит field1
и так далее...
Может кто-нибудь предложить какое-нибудь решение?
Ответы
Ответ 1
Вы можете добавить чек только для очистки, когда текст в поле не пустой (т.е. когда длина отличается от 0).
field1.addTextChangedListener(new TextWatcher() {
@Override
public void afterTextChanged(Editable s) {}
@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(s.length() != 0)
field2.setText("");
}
});
field2.addTextChangedListener(new TextWatcher() {
@Override
public void afterTextChanged(Editable s) {}
@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(s.length() != 0)
field1.setText("");
}
});
Документация для TextWatcher
здесь.
Также соблюдайте правила именования.
Ответ 2
Я знаю, что это уже давно, но кто-то может когда-нибудь столкнуться с этим.
У меня была аналогичная проблема, в которой я бы назвал setText на EditText, и onTextChanged будет вызываться, когда я этого не хочу. Моим первым решением было написать некоторый код после вызова setText(), чтобы отменить урон, причиненный слушателем. Но это было не очень элегантно.
После выполнения некоторых исследований и тестирования я обнаружил, что использование getText(). Clear() очищает текст почти так же, как setText ( "), но поскольку он не устанавливает текст, слушатель не вызывается, так что решил мою проблему. Я переключил все свои вызовы setText (" ") на getText(). Clear(), и мне больше не нужны бинты, так что, возможно, это тоже решит вашу проблему.
Попробуйте следующее:
Field1 = (EditText)findViewById(R.id.field1);
Field2 = (EditText)findViewById(R.id.field2);
Field1.addTextChangedListener(new TextWatcher() {
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) {
Field2.getText().clear();
}
});
Field2.addTextChangedListener(new TextWatcher() {
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) {
Field1.getText().clear();
}
});
Ответ 3
Если вы используете Kotlin для разработки под Android, вы можете добавить TextChangedListener()
, используя этот код:
myTextField.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) {}
})
Ответ 4
Я также столкнулся с той же проблемой и продолжаю получать полные исключения для стека, и я пришел со следующим решением.
edt_amnt_sent.addTextChangedListener(new TextWatcher() {
@Override
public void afterTextChanged(Editable s) {
if (skipOnChange)
return;
skipOnChange = true;
try {
//method
}
} catch (NumberFormatException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
skipOnChange = false;
}
}
});
edt_amnt_receive.addTextChangedListener(new TextWatcher() {
@Override
public void afterTextChanged(Editable s) {
if (skipOnChange)
return;
skipOnChange = true;
try
{
//method
} catch (NumberFormatException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
skipOnChange = false;
}
}
});
объявлено первоначально boolean skipOnChange = false;
Ответ 5
Немного поздно ответа, но вот многоразовое решение:
/**
* An extension of TextWatcher which stops further callbacks being called as
* a result of a change happening within the callbacks themselves.
*/
public abstract class EditableTextWatcher implements TextWatcher {
private boolean editing;
@Override
public final void beforeTextChanged(CharSequence s, int start,
int count, int after) {
if (editing)
return;
editing = true;
try {
beforeTextChange(s, start, count, after);
} finally {
editing = false;
}
}
protected abstract void beforeTextChange(CharSequence s, int start,
int count, int after);
@Override
public final void onTextChanged(CharSequence s, int start,
int before, int count) {
if (editing)
return;
editing = true;
try {
onTextChange(s, start, before, count);
} finally {
editing = false;
}
}
protected abstract void onTextChange(CharSequence s, int start,
int before, int count);
@Override
public final void afterTextChanged(Editable s) {
if (editing)
return;
editing = true;
try {
afterTextChange(s);
} finally {
editing = false;
}
}
public boolean isEditing() {
return editing;
}
protected abstract void afterTextChange(Editable s);
}
Поэтому, когда используется вышеописанное, любые вызовы setText()
, происходящие внутри TextWatcher, не будут вызывать снова вызов TextWatcher:
/**
* A setText() call in any of the callbacks below will not result in TextWatcher being
* called again.
*/
public class MyTextWatcher extends EditableTextWatcher {
@Override
protected void beforeTextChange(CharSequence s, int start, int count, int after) {
}
@Override
protected void onTextChange(CharSequence s, int start, int before, int count) {
}
@Override
protected void afterTextChange(Editable s) {
}
}
Ответ 6
Вы также можете использовать метод hasFocus():
public void onTextChanged(CharSequence s, int start,
int before, int count) {
if (Field2.hasfocus()){
Field1.setText("");
}
}
Протестировано это для задания колледжа, над которым я работал, чтобы преобразовать шкалы температуры, когда пользователь вводил их. Работала отлично, и это было проще.
Ответ 7
проверьте строку перед тем, как установить еще один EditText
на пустой. если Field1
пусто, то зачем нужно снова менять ("")? поэтому вы можете проверить размер своей строки с s.lenght() или любым другим решением
Другой способ, которым вы можете проверить длину строки, это:
String sUsername = Field1.getText().toString();
if (!sUsername.matches(""))
{
// do your job
}
Ответ 8
Я написал собственное расширение для этого, очень полезно для меня. (Котлин)
Вы можете написать только так:
editText.customAfterTextChanged { editable ->
//You have accessed the editable object.
}
Мое расширение:
fun EditText.customAfterTextChanged(action: (Editable?)-> Unit){
this.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}
override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}
override fun afterTextChanged(editable: Editable?) {
action(editable)
}
})}