Reputation: 12444
Consider:
TextView textView = new TextView(context);
textView.addTextChangedListener(new TextWatcher() {
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
}
@Override
public void afterTextChanged(Editable s) {
s.append("A");
}
});
If we add a TextWatcher
to a TextView
, and I want to append a letter to this TextView
, every time the user writes a letter in it, but this keeps calling the TextWatcher
Listener, so on to StackOverFlow error
, so how can I append text without calling the TextWatcher
Listener again?
Upvotes: 11
Views: 14420
Reputation: 62519
Some pseudocode so you can do this:
Just change the focus...
So like this:
tv.isFocusable = false
tv.setText("my new text")
tv.isFocusable = true // Maybe post this to the message queue, so other jobs finish fist.
// Later on in your listener:
if(tv.isFocusable && tv.hasFocus())
// Do something
else ignore
Upvotes: 0
Reputation: 3151
Another way to avoid a stack overflow:
TextView textView = new TextView(context);
textView.addTextChangedListener(new TextWatcher() {
boolean editing = false;
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count,int after) {
}
@Override
public void afterTextChanged(Editable s) {
if (!editing){
editing = true;
s.append("A");
editing = false;
}
}
});
Upvotes: 8
Reputation: 1989
Kotlin Version
editText.addTextChangedListener(object: TextWatcher {
override fun afterTextChanged(s: Editable?) {
if (s.toString().isNotBlank()) {
val formattedValue: String = // Do some formatting
editText.removeTextChangedListener(this)
editText.setText(formattedValue)
editText.setSelection(editText.text.toString().length)
editText.addTextChangedListener(this)
}
}
override fun beforeTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) { }
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
}
})
Upvotes: -2
Reputation: 10194
It's easy:
@Override
public void afterTextChanged(Editable s) {
editText.removeTextChangedListener(this);
//Any modifications at this point will not be detected by TextWatcher,
//so no more StackOverflowError
s.append("A");
editText.addTextChangedListener(this);
}
Upvotes: 32
Reputation: 10533
The documentation of afterTextChanged says:
This method is called to notify you that, somewhere within s, the text has been changed. It is legitimate to make further changes to s from this callback, but be careful not to get yourself into an infinite loop, because any changes you make will cause this method to be called again recursively. (You are not told where the change took place because other afterTextChanged() methods may already have made other changes and invalidated the offsets. But if you need to know here, you can use setSpan(Object, int, int, int)
in onTextChanged(CharSequence, int, int, int)
to mark your place and then look up from here where the span ended up.
So, with every s.append("A")
you call afterTextChanged()
again and so on.
Upvotes: 5