如何在不触发Text Watcher的情况下更改EditText文本?

use*_*767 88 java android event-handling infinite-loop

我有一个EditText带有客户文本观察器的字段.在一段代码中,我需要更改我使用的EditText中的值.setText("whatever").

问题是,一旦我进行了更改,afterTextChanged调用的方法就会创建一个无限循环.如何在不触发afterTextChanged的情况下更改文本?

我需要在afterTextChanged方法中的文本,所以不建议删除TextWatcher.

Wil*_*zel 94

您可以检查当前哪个View具有焦点,以区分用户和程序触发的事件.

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

    //...
});
Run Code Online (Sandbox Code Playgroud)

编辑:正如LairdPleng正确提到的,如果myEditText已经有焦点并且您以编程方式更改文本,则此方法无效.因此,在调用之前clearFocus()你应该叫setText(...)焯芬表示,这解决了这个问题为好.

  • 不理想。如果我想 setText() 而不触发侦听器,即使 edittext 具有焦点怎么办? (3认同)
  • 奇迹般有效 !必须是可接受的答案) (2认同)

Cas*_*alT 64

您可以取消注册观察者,然后重新注册它.

或者,您可以设置一个标志,以便您的观察者知道您何时自己更改了文本(因此应该忽略它).


Cha*_*Him 26

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

用法:

et_text.addTextChangedListener(new MyTextWatcher(et_text));
Run Code Online (Sandbox Code Playgroud)

如果您使用editText.setText()而不是editable.replace(),则在快速输入文本时可能会感到有点滞后.

  • 为什么这被否决了?这是解决我的问题的完美解决方案,而其他问题则不起作用。我要补充的是,没有必要子类化 TextWatcher 才能使该解决方案发挥作用。谢谢陈振谦。 (2认同)

Jef*_*man 14

很容易修复... 只要你的逻辑推导出新的编辑文本值是幂等的(它可能会,但只是说).在侦听器方法中,如果当前值与上次修改值不同,则仅修改编辑文本.

例如,

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);
    }
  }
};
Run Code Online (Sandbox Code Playgroud)


Ale*_*lia 8

您可以使用 Kotlin DSL 语法来获得通用解决方案:

fun TextView.applyWithDisabledTextWatcher(textWatcher: TextWatcher, codeBlock: TextView.() -> Unit) {
    this.removeTextChangedListener(textWatcher)
    codeBlock()
    this.addTextChangedListener(textWatcher)
}
Run Code Online (Sandbox Code Playgroud)

在您的 TextWatcher 中,您可以将其用作:

editText.applyWithDisabledTextWatcher(this) {
    text = formField.name
}
Run Code Online (Sandbox Code Playgroud)


Art*_*elo 7

我用这种方式:

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);
                }
            }
        });
Run Code Online (Sandbox Code Playgroud)

并且每次需要以编程方式更改文本时,请先清除焦点

mEditText.clearFocus();
mEditText.setText(lastAddress.complement);
Run Code Online (Sandbox Code Playgroud)


Lev*_*yan 7

使用filed 可以轻松解决该问题tag,您甚至不必处理editText 的焦点。

以编程方式设置文本和标签

editText.tag = "dummyTag"
editText.setText("whatever")
editText.tag = null
Run Code Online (Sandbox Code Playgroud)

检查tagonTextChanged 中的

override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
    if (editText.tag == null) {
       // your code
    }
}
Run Code Online (Sandbox Code Playgroud)


小智 5

这对我很有用

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) { }
    });
Run Code Online (Sandbox Code Playgroud)