android en Text Change Listener

265

Tengo una situación, donde hay dos campos. field1y field2. Todo lo que quiero hacer está vacío field2cuando field1se cambia y viceversa. Entonces, al final, solo un campo tiene contenido.

field1 = (EditText)findViewById(R.id.field1);
field2 = (EditText)findViewById(R.id.field2);

field1.addTextChangedListener(new TextWatcher() {

   public void afterTextChanged(Editable s) {}

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

   public void onTextChanged(CharSequence s, int start,
     int before, int count) {
      field2.setText("");
   }
  });

field2.addTextChangedListener(new TextWatcher() {

   public void afterTextChanged(Editable s) {}

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

   public void onTextChanged(CharSequence s, int start,
     int before, int count) {
     field1.setText("");
   }
  });

Funciona bien si hay que adjuntar addTextChangedListenera la field1única, pero cuando lo hago por los dos campos de la aplicación se bloquea. Obviamente porque intentan cambiarse indefinidamente. Una vez que los field1cambios se borran field2en este momento, field2se cambian para que se borren field1y así sucesivamente ...

¿Alguien puede sugerir alguna solución?

inrob
fuente
para los nuevos usuarios, opten por el enlace de datos bidireccional usando un campo de cadena observable, porque toda la solución provista aquí puede producir starting waiting blocking gc alloceste tipo de error, que incluso puede provocar un bloqueo y bloqueo ... así que vaya por el enlace de datos, eso es seguro y recomendado por google ahora ..
Maifee Ul Asad

Respuestas:

460

Puede agregar un cheque para borrar solo cuando el texto en el campo no está vacío (es decir, cuando la longitud es diferente de 0).

field1.addTextChangedListener(new TextWatcher() {

   @Override
   public void afterTextChanged(Editable s) {}

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

   @Override    
   public void onTextChanged(CharSequence s, int start,
     int before, int count) {
      if(s.length() != 0)
        field2.setText("");
   }
  });

field2.addTextChangedListener(new TextWatcher() {

   @Override
   public void afterTextChanged(Editable s) {}

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

   @Override
   public void onTextChanged(CharSequence s, int start,
     int before, int count) {
      if(s.length() != 0)
         field1.setText("");
   }
  });

Documentación para TextWatcher aquí .

También respete las convenciones de nomenclatura .

usuario2336315
fuente
1
cómo detectar después de que todo el campo haya cambiado, porque detecta cada vez que cambia, cuando se presiona cualquier botón.
Rafael Guimarães
20

Sé que esto es viejo, pero alguien podría volver a encontrarlo algún día.

Tuve un problema similar en el que llamaría a setText en EditText y onTextChanged se llamaría cuando no lo quisiera. Mi primera solución fue escribir un código después de llamar a setText () para deshacer el daño hecho por el oyente. Pero eso no fue muy elegante. Después de investigar y probar, descubrí que el uso de getText (). Clear () borra el texto de la misma manera que setText (""), pero como no está configurando el texto, no se llama al oyente, de modo que resuelto mi problema Cambié todas mis llamadas de setText ("") a getText (). Clear () y ya no necesitaba las vendas, así que quizás eso también resuelva su problema.

Prueba esto:

Field1 = (EditText)findViewById(R.id.field1);
Field2 = (EditText)findViewById(R.id.field2);

Field1.addTextChangedListener(new TextWatcher() {

   public void afterTextChanged(Editable s) {}

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

   public void onTextChanged(CharSequence s, int start,
     int before, int count) {
      Field2.getText().clear();
   }
  });

Field2.addTextChangedListener(new TextWatcher() {

   public void afterTextChanged(Editable s) {}

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

   public void onTextChanged(CharSequence s, int start,
     int before, int count) {
     Field1.getText().clear();
   }
  });
RTHarston
fuente
11

Si está utilizando Kotlin para el desarrollo de Android, puede agregar TextChangedListener()usando este código:

myTextField.addTextChangedListener(object : TextWatcher{
        override fun afterTextChanged(s: Editable?) {}

        override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}

        override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
    })
iHulk
fuente
5

Un poco tarde de una respuesta, pero aquí hay una solución reutilizable:

/**
 * 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;
        }
    }

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

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

    protected abstract void afterTextChange(Editable s);
}

Entonces, cuando se usa lo anterior, cualquier setText()llamada que ocurra dentro del TextWatcher no dará como resultado que se vuelva a llamar al TextWatcher:

/**
 * A setText() call in any of the callbacks below will not result in TextWatcher being 
 * called again.
 */
public class MyTextWatcher extends EditableTextWatcher {

    @Override
    protected void beforeTextChange(CharSequence s, int start, int count, int after) {
    }

    @Override
    protected void onTextChange(CharSequence s, int start, int before, int count) {
    }

    @Override
    protected void afterTextChange(Editable s) {
    }
}
Eurig Jones
fuente
5

También me he enfrentado al mismo problema y sigo recibiendo stackOverflowexcepciones, y vengo con la siguiente solución.

edt_amnt_sent.addTextChangedListener(new TextWatcher() {    
    @Override
    public void afterTextChanged(Editable s) {
        if (skipOnChange)
            return;

        skipOnChange = true;
        try {
            //method
        } catch (NumberFormatException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            skipOnChange = false;
        }
    }
});

edt_amnt_receive.addTextChangedListener(new TextWatcher() {

    @Override
    public void afterTextChanged(Editable s) {

        if (skipOnChange)
            return;

        skipOnChange = true;
        try {
            //method
        } catch (NumberFormatException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            skipOnChange = false;
        }
    }
});

declarado inicialmente booleano skipOnChange = false;

Sumit
fuente
1
"stack full" Creo que te refieres a Stack Overflow;)
Un droide
4

También puede usar el método hasFocus ():

public void onTextChanged(CharSequence s, int start,
     int before, int count) {
     if (Field2.hasfocus()){
         Field1.setText("");
     }
   }

Probé esto para una tarea universitaria en la que estaba trabajando para convertir escalas de temperatura a medida que el usuario las ingresaba. Funcionó perfectamente, y es mucho más simple.

renam
fuente
1
¿Qué pasa con editText.setText cuando el usuario ingresa en él? EditText tiene foco en este caso
Evgenii Vorobei
mejor solución .
Syed Hissaan
3

marque String antes de configurar otro EditTextpara vaciarlo. si Field1está vacío, ¿por qué necesita cambiar nuevamente a ("")? para que pueda verificar el tamaño de su cadena con s.lenght () o cualquier otra solución

Otra forma de comprobar la longitud de String es:

String sUsername = Field1.getText().toString();
if (!sUsername.matches(""))
{
// do your job
}
Shayan Pourvatan
fuente
2

Escribí mi propia extensión para esto, muy útil para mí. (Kotlin)

Solo puedes escribir así:

editText.customAfterTextChanged { editable -> 
    //You have accessed the editable object. 
}

Mi extensión:

fun EditText.customAfterTextChanged(action: (Editable?)-> Unit){
    this.addTextChangedListener(object : TextWatcher {
       override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}
       override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}
       override fun afterTextChanged(editable: Editable?) {
        action(editable)
    }
})}
Burak Dizlek
fuente
2
editText.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {

            }
            @Override
            public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
                if (noteid != -1) {
                    MainActivity.notes.set(noteid, String.valueOf(charSequence));
                    MainActivity.arrayAdapter.notifyDataSetChanged();
                }
            }
            @Override
            public void afterTextChanged(Editable editable) {

            }
        });

en este código, noteid es básicamente argumentos retirados que se introducen en la sangría o se pasan a través de la sangría.

  Intent intent = getIntent();
         noteid = intent.getIntExtra("noteid", -1);

El código en el lado negativo es básicamente el código adicional, si desea comprender más claramente.

how to make the menu or insert the menu in our code , 
    create the  menu folder this the folder created by going into the raw
    ->rightclick->
    directory->name the folder as you wish->
    then click on the directory formed->
    then click on new file and then name for file as you wish ie the folder name file
    and now type the 2 lines code in it and see the magic.

nuevo código de actividad llamado NoteEditor.java para fines de edición, mi aplicación es básicamente la aplicación de notas.

package com.example.elavi.notes;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.widget.EditText;
import android.widget.Toast;

import static android.media.CamcorderProfile.get;
public class NoteEditorActivity extends AppCompatActivity {
    EditText editText;
    int noteid;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_note_editor);
        editText = findViewById(R.id.editText);
        Intent intent = getIntent();
         noteid = intent.getIntExtra("noteid", -1);
        if (noteid != -1) {
            String text = MainActivity.notes.get(noteid);
            editText.setText(text);

           Toast.makeText(getApplicationContext(),"The arraylist content is"+MainActivity.notes.get(noteid),Toast.LENGTH_SHORT).show();
        }
        else
        {
            Toast.makeText(getApplicationContext(),"Here we go",Toast.LENGTH_SHORT).show();
            MainActivity.notes.add("");
            noteid=MainActivity.notes.size()-1;
        }
        editText.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {

            }
            @Override
            public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
                if (noteid != -1) {
                    MainActivity.notes.set(noteid, String.valueOf(charSequence));
                    MainActivity.arrayAdapter.notifyDataSetChanged();
                }
            }
            @Override
            public void afterTextChanged(Editable editable) {

            }
        });
    }
}
Garg lujoso
fuente
1

En Kotlin simplemente use la función de extensión KTX : (Utiliza TextWatcher)

yourEditText.doOnTextChanged { text, start, count, after -> 
        // action which will be invoked when the text is changing
    }


importación core-KTX:

implementation "androidx.core:core-ktx:1.2.0"
Francisco
fuente
1

Podemos eliminar TextWatcher para un campo justo antes de editar su texto y luego agregarlo nuevamente después de editar el texto.

Declare Text Watchers para field1 y field2 como variables separadas para darles un nombre: por ejemplo, para field1

private TextWatcher Field_1_Watcher = new TextWatcher() {
    @Override
    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
    }

    @Override
    public void afterTextChanged(Editable s) {
    }

    @Override
    public void onTextChanged(CharSequence s, int start, int before, int count) {

    }

};

a continuación, añadir el observador usando su nombre: field1.addTextChangedListener(Field_1_Watcher)para campo1 , y field2.addTextChangedListener(Field_2_Watcher)para campo2

Antes de cambiar el texto del campo2, elimine el TextWatcher: field2.removeTextChangedListener(Field_2_Watcher) cambie el texto: field2.setText("")

luego agregue el TextWatcher de nuevo: field2.addTextChangedListener(Field_2_Watcher)

Haz lo mismo para el otro campo

Keith Kiarie
fuente
-3

Agregar fondo dinámicamente en el onCreatemétodo:

getWindow().setBackgroundDrawableResource(R.drawable.background);

También elimine el fondo de XML.

Ankit Kumar
fuente