如何在不触发Text Watcher的情况下更改EditText文本?
我有一个EditText
字段,上面有一个Customer Text Watcher。 在一段代码中,我需要改变EditText中的值,我使用.setText("whatever")
。
问题是一旦我做了这个改变afterTextChanged
方法得到调用创build了一个无限循环。 如何在不触发afterTextChanged的情况下更改文本?
我需要在afterTextChanged方法中的文本,所以不build议删除TextWatcher
。
您可以注销观察者,然后重新注册。
或者,你可以设置一个标志,以便你的观察者知道你什么时候改变了文本(因此应该忽略它)。
您可以检查哪个视图当前有焦点来区分用户和程序触发的事件。
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(...)
,应该像Chack所说的那样调用myEditText.clearFocus()
,这也解决了这个问题。
简单的技巧来解决… 只要你的逻辑推导出新的编辑文本值是幂等的 (这可能是,但只是说)。 在您的侦听器方法中,如果当前值与上次修改值不同,则只能修改编辑文本。
例如,
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); } } };
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 setText et.removeTextChangedListener(this); et.setText("text"); // Re-register self after setText et.addTextChangedListener(this); } }
用法:
et_text.addTextChangedListener(new MyTextWatcher(et_text));
更新:
要更顺利地更新文本,请更换
et.setText("text");
同
s.replace(0, s.length(), "text");
嗨,如果你需要保持专注于EditText
更改文本,你可以请求重点。 这对我工作:
if (getCurrentFocus() == editText) { editText.clearFocus(); editText.setText("..."); editText.requestFocus(); }
尝试这个逻辑:我想setText(“”),而不会无限循环,这段代码为我工作。 我希望你可以修改这个以适合你的要求
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 } });
我的变体:
public class CustomEditText extends AppCompatEditText{ TextWatcher l; public CustomEditText(Context context, AttributeSet attrs) { super(context, attrs); } public void setOnTextChangeListener(TextWatcher l) { try { removeTextChangedListener(this.l); } catch (Throwable e) {} addTextChangedListener(l); this.l = l; } public void setNewText(CharSequence s) { final TextWatcher l = this.l; setOnTextChangeListener(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) { } }); setText(s); post(new Runnable() { @Override public void run() { setOnTextChangeListener(l); } }); } }
设置监听只使用setOnTextChangeListener()和设置文本只使用setNewText(我想覆盖setText(),但它是最后的)
从文本更改的侦听器中设置文本时,可能会发生无限循环。 如果是这样,也许最好不要从那里设置文本。 所以你会解决循环问题,没有理由绕过或消耗事件。
我创build了一个抽象类,它可以缓解EditText对TextWatcher的修改时出现的循环问题。
/** * 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; } } 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; } } 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; } abstract void afterTextChange(Editable s); }
您应该确保您的文本更改的实现是稳定的,不会更改文本如果不需要更改。 通常情况下,这将是任何已经通过观察者的内容。
最常见的错误是在关联的EditText或Editable中设置新文本,即使文本实际上并未发生更改。
最重要的是,如果您对“可编辑”而不是某个特定的“视图”进行了更改,则可以轻松地重新使用观察器,也可以通过一些unit testing进行单独testing,以确保获得所需的结果。
由于Editable是一个接口,你甚至可以使用它的一个虚拟实现,当testing应该是稳定的内容时,如果调用了它的任何方法来尝试改变其内容,就会抛出一个RuntimeException。