Как я могу изменить текст EditText без запуска Text Watcher? - PullRequest
80 голосов
/ 22 февраля 2012

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

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

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

Ответы [ 13 ]

82 голосов
/ 15 октября 2015

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

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

myEditText.addTextChangedListener(new TextWatcher() {

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

    //...
});

Редактировать: Как LairdPleng правильно упомянуто, этоне работает, если myEditText уже имеет фокус, и вы программно изменяете текст.Итак, перед вызовом myEditText.setText(...) вы должны позвонить myEditText.clearFocus(), как сказал Чак , что также решает эту проблему.

58 голосов
/ 22 февраля 2012

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

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

23 голосов
/ 30 декабря 2015
public class MyTextWatcher implements TextWatcher {
    private EditText et;

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

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

        // The trick to update text smoothly.
        s.replace(0, s.length(), "text");

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

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

et_text.addTextChangedListener(new MyTextWatcher(et_text));

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

13 голосов
/ 29 мая 2013

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

например.,

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);
    }
  }
};
3 голосов
/ 03 августа 2017

Привет, если вам нужно сосредоточиться на EditText изменении текста, вы можете запросить фокус. Это сработало для меня:

if (getCurrentFocus() == editText) {
    editText.clearFocus();
    editText.setText("...");
    editText.requestFocus();
}
2 голосов
/ 07 августа 2018

Я так использую:

mEditText.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) {
                if (mEditText.isFocused()) { //<-- check if is focused 
                    mEditText.setTag(true);
                }
            }
        });

И каждый раз, когда вам нужно изменить текст программно, сначала очистите фокус

mEditText.clearFocus();
mEditText.setText(lastAddress.complement);
1 голос
/ 31 августа 2015

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

        final EditText text= (EditText)findViewById(R.id.text);
        text.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) {
            if(s.toString().isEmpty())return;
            text.setText("");
            //your code
        }
    });
0 голосов
/ 19 июля 2019

Это хорошо работает для меня

EditText inputFileName; // = (EditText)findViewbyId(R.id...)
inputFileName.addTextChangedListener(new TextWatcher() {
        public void afterTextChanged(Editable s) {

            //unregistering for event in order to prevent infinity loop
            inputFileName.removeTextChangedListener(this);

            //changing input's text
            String regex = "[^a-z0-9A-Z\\s_\\-]";
            String fileName = s.toString();
            fileName = fileName.replaceAll(regex, "");
            s.replace(0, s.length(), fileName); //here is setting new text

            Log.d("tag", "----> FINAL FILE NAME: " + fileName);

            //registering back for text changes
            inputFileName.addTextChangedListener(this);
        }

        public void beforeTextChanged(CharSequence s, int start, int count, int after) { }

        public void onTextChanged(CharSequence s, int start, int before, int count) { }
    });
0 голосов
/ 10 мая 2019

Вы можете использовать синтаксис Kotlin DSL, чтобы иметь общее решение для этого:

fun TextView.applyWithDisabledTextWatcher(textWatcher: TextWatcher, codeBlock: TextView.() -> Unit) {
    this.removeTextChangedListener(textWatcher)
    codeBlock()
    this.addTextChangedListener(textWatcher)
}

А внутри вашего TextWatcher вы можете использовать его как:

editText.applyWithDisabledTextWatcher(this) {
    text = formField.name
}
0 голосов
/ 27 марта 2018

Вот удобный класс, который предоставляет более простой интерфейс, чем TextWatcher, для обычного случая, когда вы хотите видеть изменения по мере их возникновения. Это также позволяет игнорировать следующее изменение в качестве запрошенного OP.

public class EditTexts {
    public final static class EditTextChangeListener implements TextWatcher {
        private final Consumer<String> onEditTextChanged;
        private boolean ignoreNextChange = false;
        public EditTextChangeListener(Consumer<String> onEditTextChanged){
            this.onEditTextChanged = onEditTextChanged;
        }
        public void ignoreNextChange(){
            ignoreNextChange = true;
        }
        @Override public void beforeTextChanged(CharSequence __, int ___, int ____, int _____) { }
        @Override public void onTextChanged(CharSequence __, int ___, int ____, int _____) { }
        @Override public void afterTextChanged(Editable s) {
            if (ignoreNextChange){
                ignoreNextChange = false;
            } else {
                onEditTextChanged.accept(s.toString());
            }
        }
    }
}

Используйте это так:

EditTexts.EditTextChangeListener listener = new EditTexts.EditTextChangeListener(s -> doSomethingWithString(s));
editText.addTextChangedListener(listener);

Всякий раз, когда вы хотите изменить содержимое editText, не вызывая каскад рекурсивных изменений, сделайте следующее:

listener.ignoreNextChange();
editText.setText("whatever"); // this won't trigger the listener
...