Android

How can I change the EditText text without triggering the Text Watcher?

Как я могу изменить текст EditText без запуска программы просмотра текста?

У меня есть EditText поле с пользовательским средством просмотра текста. В фрагменте кода мне нужно изменить значение в EditText, которое я использую.setText("whatever").

Проблема в том, что как только я вношу это изменение, afterTextChanged вызывается метод, который создает бесконечный цикл. Как я могу изменить текст, не запуская afterTextChanged ?

Мне нужен текст в методе afterTextChanged, поэтому не предлагайте удалять TextWatcher.

Переведено автоматически
Ответ 1

Краткий ответ

Вы можете проверить, на каком представлении в данный момент сосредоточено внимание, чтобы различать события, запускаемые пользователем, и события, запускаемые программой.

EditText myEditText = (EditText) findViewById(R.id.myEditText);

myEditText.addTextChangedListener(new TextWatcher() {

@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
if (myEditText.hasFocus()) {
// is only executed if the EditText was directly changed by the user
}
}

//...
});

Длинный ответ

В дополнение к короткому ответу: в случае, если myEditText уже есть фокус, когда вы программно изменяете текст, который вы должны вызвать clearFocus(), затем вы вызываете setText(...) и после этого повторно запрашиваете фокус. Было бы неплохо поместить это в служебную функцию:

void updateText(EditText editText, String text) {
boolean focussed = editText.hasFocus();
if (focussed) {
editText.clearFocus();
}
editText.setText(text);
if (focussed) {
editText.requestFocus();
}
}

Для Kotlin:

Поскольку Kotlin поддерживает функции расширения, ваша служебная функция может выглядеть следующим образом:

fun EditText.updateText(text: String) {
val focussed = hasFocus()
if (focussed) {
clearFocus()
}
setText(text)
if (focussed) {
requestFocus()
}
}
Ответ 2

Вы могли бы отменить регистрацию средства просмотра, а затем зарегистрировать его повторно.

В качестве альтернативы вы могли бы установить флаг, чтобы ваш наблюдатель знал, когда вы только что изменили текст самостоятельно (и, следовательно, должен игнорировать его).

Ответ 3

Java:

public class MyTextWatcher implements TextWatcher {
private EditText editText;

// Pass the EditText instance to TextWatcher by constructor
public MyTextWatcher(EditText editText) {
this.editText = editText;
}

@Override
public void afterTextChanged(Editable e) {
// Unregister self before update
editText.removeTextChangedListener(this);

// The trick to update text smoothly.
e.replace(0, e.length(), e.toString());

// Re-register self after update
editText.addTextChangedListener(this);
}

...
}

Kotlin:

class MyTextWatcher(private val editText: EditText) : TextWatcher {

override fun afterTextChanged(e: Editable) {
editText.removeTextChangedListener(this)
e.replace(0, e.length, e.toString())
editText.addTextChangedListener(this)
}

...
}

Использование:

et_text.addTextChangedListener(new MyTextWatcher(et_text));

Вы можете почувствовать небольшую задержку при быстром вводе текста, если используете EditText.setText() вместо editable.replace().

Ответ 4

Простой трюк для исправления ... пока ваша логика для получения нового значения edit text идемпотентна (что, вероятно, так и было бы, но просто говорю). В вашем методе прослушивания изменяйте текст редактирования, только если текущее значение отличается от значения, которое вы изменяли в последний раз.

например,

TextWatcher tw = new TextWatcher() {
private String lastValue = "";

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

// Return value of getNewValue() must only depend
// on the input and not previous state
String newValue = getNewValue(editText.getText().toString());
if (!newValue.equals(lastValue)) {
lastValue = newValue;

editText.setText(newValue);
}
}
};
2023-11-26 22:23 java android