java - textos - ¿Cómo puedo cambiar el texto de Editar Texto sin activar el Observador de Texto?
rotar texto en autocad (12)
Tengo un campo EditText
Texto con un Observador de Texto del Cliente en él. En un fragmento de código necesito cambiar el valor en el EditText que hago usando .setText("whatever")
.
El problema es que tan pronto como hago ese cambio, se llama al método afterTextChanged
que creó un bucle infinito. ¿Cómo puedo cambiar el texto sin que se active después de TextChanged?
Necesito el texto en el método afterTextChanged, así que no sugiera eliminar el TextWatcher
.
Aquí hay una clase práctica que proporciona una interfaz más simple que TextWatcher para el caso normal de querer ver los cambios a medida que ocurren. También permite ignorar el siguiente cambio según lo solicitado por el 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());
}
}
}
}
Úsalo así:
EditTexts.EditTextChangeListener listener = new EditTexts.EditTextChangeListener(s -> doSomethingWithString(s));
editText.addTextChangedListener(listener);
Cuando quiera modificar el contenido de editText
sin causar una cascada de ediciones recursivas, haga esto:
listener.ignoreNextChange();
editText.setText("whatever"); // this won''t trigger the listener
Debe asegurarse de que su implementación de cambios de texto sea estable y no cambie el texto si no es necesario realizar cambios. Normalmente ese sería cualquier contenido que ya haya pasado por el observador una vez.
El error más común es establecer un nuevo texto en el EditText o Editable asociado, aunque el texto no haya cambiado realmente.
Además de eso, si realiza cambios en la Vista Editable en lugar de en alguna Vista específica, puede volver a utilizar fácilmente a su observador, y también puede probarlo de forma aislada con algunas pruebas unitarias para garantizar que tenga el resultado que desea.
Dado que Editable es una interfaz, incluso podría usar una implementación ficticia de la misma que arroja una RuntimeException si se llama a alguno de sus métodos que intentan cambiar su contenido, al probar contenido que debería ser estable.
He creado una clase abstracta que mitiga el problema cíclico de cuando se realiza una modificación al EditText a través de un 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);
}
Hola, si necesita mantenerse enfocado en el texto de cambio de Texto de EditText
, puede solicitar el enfoque. Esto funcionó para mí:
if (getCurrentFocus() == editText) {
editText.clearFocus();
editText.setText("...");
editText.requestFocus();
}
Mi variante:
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);
}
});
}
}
Establecer escuchas solo usando setOnTextChangeListener () y configurar texto solo usando setNewText (quería reemplazar a setText (), pero es definitivo)
Podría anular el registro del observador y luego volver a registrarlo.
Alternativamente, puede establecer una bandera para que su observador sepa cuándo usted mismo acaba de cambiar el texto (y, por lo tanto, debería ignorarlo).
Puede verificar qué Vista tiene actualmente el enfoque para distinguir entre eventos activados por el usuario y por el programa.
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
}
}
//...
});
Edición: Como LairdPleng mencionó correctamente, esto no funciona si myEditText
ya tiene el enfoque y usted cambia el texto mediante programación. Entonces, antes de llamar a myEditText.setText(...)
debe llamar a myEditText.clearFocus()
como dijo Chack , que también resuelve este problema.
Se puede producir un bucle infinito cuando se configura el texto desde el oyente cambiado de texto. Si este es el caso, tal vez sea mejor no configurar el texto desde allí en primer lugar. Así que resolverá el problema del bucle y no hay razón para omitir o consumir el evento.
Truco fácil de arreglar ... siempre que su lógica para derivar el nuevo valor de edición de texto sea idempotente (lo que probablemente sería, pero solo decir). En su método de escucha, solo modifique el texto de edición si el valor actual es diferente a la última vez que modificó el valor.
p.ej,
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);
}
}
};
Yo uso de esa manera:
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);
}
}
});
Y cada vez que necesite cambiar el texto programáticamente, primero despeje el enfoque
mEditText.clearFocus();
mEditText.setText(lastAddress.complement);
intente esta lógica: quería establecerText ("") sin ir a un bucle infinito y este código funciona para mí. Espero que pueda modificar esto para adaptarse a sus necesidades.
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 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);
}
}
Uso:
et_text.addTextChangedListener(new MyTextWatcher(et_text));
Actualizar:
Para actualizar el texto más suavemente, reemplace
et.setText("text");
con
s.replace(0, s.length(), "text");