Evento clave de Android EditText eliminar (retroceso)

¿Cómo puedo detectar el evento clave de eliminación (retroceso) para un editText? Intenté usar TextWatcher, pero cuando editText está vacío, cuando presiono la tecla borrar, no pasa nada. Quiero detectar la tecla borrar presionar un editText incluso si no tiene texto.

NOTA: onKeyListener no funciona para teclados suaves.

Puede configurar OnKeyListener para editText para que pueda detectar cualquier pulsación de tecla
EDITAR: Un error común que estamos comprobando KeyEvent.KEYCODE_BACK para el backspace , pero realmente es KeyEvent.KEYCODE_DEL (¡Realmente ese nombre es muy confuso!)

 editText.setOnKeyListener(new OnKeyListener() { @Override public boolean onKey(View v, int keyCode, KeyEvent event) { //You can identify which key pressed buy checking keyCode value with KeyEvent.KEYCODE_ if(keyCode == KeyEvent.KEYCODE_DEL) { //this is for backspace } return false; } }); 

Ha pasado un tiempo desde que lo preguntaste, pero tuve el mismo problema. Como ya mencionó Estel, el problema con los oyentes clave es que solo funcionan con teclados de hardware. Para hacer esto con un IME (teclado virtual) , la solución es un poco más elaborada.

El único método que queremos anular es sendKeyEvent en la clase InputConnection . Este método se invoca cuando ocurren eventos clave en un IME. Pero para anular esto, necesitamos implementar un EditText personalizado que anule el método onCreateInputConnection , envolviendo el objeto InputConnection predeterminado en una clase de proxy. : |

Suena complicado, pero aquí está el ejemplo más simple que pude idear:

 public class ZanyEditText extends EditText { private Random r = new Random(); public ZanyEditText(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } public ZanyEditText(Context context, AttributeSet attrs) { super(context, attrs); } public ZanyEditText(Context context) { super(context); } public void setRandomBackgroundColor() { setBackgroundColor(Color.rgb(r.nextInt(256), r.nextInt(256), r .nextInt(256))); } @Override public InputConnection onCreateInputConnection(EditorInfo outAttrs) { return new ZanyInputConnection(super.onCreateInputConnection(outAttrs), true); } private class ZanyInputConnection extends InputConnectionWrapper { public ZanyInputConnection(InputConnection target, boolean mutable) { super(target, mutable); } @Override public boolean sendKeyEvent(KeyEvent event) { if (event.getAction() == KeyEvent.ACTION_DOWN && event.getKeyCode() == KeyEvent.KEYCODE_DEL) { ZanyEditText.this.setRandomBackgroundColor(); // Un-comment if you wish to cancel the backspace: // return false; } return super.sendKeyEvent(event); } } } 

La línea con la llamada a setRandomBackgroundColor es donde ocurre mi acción especial de retroceso. En este caso, cambiando el color de fondo de EditText .

Si está inflando esto desde XML, recuerde usar el nombre completo del paquete como la etiqueta:

  

Esto es solo una adición a la respuesta de Idris, añadiendo la anulación a deleteSurroundingText también. Encontré más información sobre eso aquí: Android: Retroceso en WebView / BaseInputConnection

 package com.elavon.virtualmerchantmobile.utils; import java.util.Random; import android.content.Context; import android.graphics.Color; import android.util.AttributeSet; import android.view.KeyEvent; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputConnection; import android.view.inputmethod.InputConnectionWrapper; import android.widget.EditText; public class ZanyEditText extends EditText { private Random r = new Random(); public ZanyEditText(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } public ZanyEditText(Context context, AttributeSet attrs) { super(context, attrs); } public ZanyEditText(Context context) { super(context); } public void setRandomBackgroundColor() { setBackgroundColor(Color.rgb(r.nextInt(256), r.nextInt(256), r .nextInt(256))); } @Override public InputConnection onCreateInputConnection(EditorInfo outAttrs) { return new ZanyInputConnection(super.onCreateInputConnection(outAttrs), true); } private class ZanyInputConnection extends InputConnectionWrapper { public ZanyInputConnection(InputConnection target, boolean mutable) { super(target, mutable); } @Override public boolean sendKeyEvent(KeyEvent event) { if (event.getAction() == KeyEvent.ACTION_DOWN && event.getKeyCode() == KeyEvent.KEYCODE_DEL) { ZanyEditText.this.setRandomBackgroundColor(); // Un-comment if you wish to cancel the backspace: // return false; } return super.sendKeyEvent(event); } @Override public boolean deleteSurroundingText(int beforeLength, int afterLength) { // magic: in latest Android, deleteSurroundingText(1, 0) will be called for backspace if (beforeLength == 1 && afterLength == 0) { // backspace return sendKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL)) && sendKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DEL)); } return super.deleteSurroundingText(beforeLength, afterLength); } } } 

Aquí está mi solución fácil, que funciona para todas las API:

 private int previousLength; private boolean backSpace; // ... @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { previousLength = s.length(); } @Override public void onTextChanged(CharSequence s, int start, int before, int count) { } @Override public void afterTextChanged(Editable s) { backSpace = previousLength > s.length(); if (backSpace) { // do your stuff ... } } 

ACTUALIZACIÓN 17.04.18 .
Como se señala en los comentarios, esta solución no rastrea la retroceso de la pantalla si EditText está vacío (igual que la mayoría de las otras soluciones).
Sin embargo, es suficiente para la mayoría de los casos de uso.
PD: si tuviera que crear algo similar hoy, lo haría:

 public abstract class TextWatcherExtended implements TextWatcher { private int lastLength; public abstract void afterTextChanged(Editable s, boolean backSpace); @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { lastLength = s.length(); } @Override public void afterTextChanged(Editable s) { afterTextChanged(s, lastLength > s.length()); } } 

Entonces solo úsalo como un TextWatcher regular:

  editText.addTextChangedListener(new TextWatcherExtended() { @Override public void afterTextChanged(Editable s, boolean backSpace) { // Here you are! You got missing "backSpace" flag } @Override public void onTextChanged(CharSequence s, int start, int before, int count) { // Do something useful if you wish. // Or override it in TextWatcherExtended class if want to avoid it here } }); 

Envié 2 días para encontrar una solución y descubrí una que funciona 🙂 (en las teclas progtwigbles)

 public TextWatcher textWatcher = 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) { if (count == 0) { //Put your code here. //Runs when delete/backspace pressed on soft key (tested on htc m8) //You can use EditText.getText().length() to make if statements here } } @Override public void afterTextChanged(Editable s) { } } 

Después de agregar el textwatcher a su EditText:

 yourEditText.addTextChangedListener(textWatcher); 

Espero que funcione en otros dispositivos Android también (Samsung, LG, etc.).

Ejemplo de crear EditText con TextWatcher

 EditText someEdit=new EditText(this); //create TextWatcher for our EditText TextWatcher1 TW1 = new TextWatcher1(someEdit); //apply our TextWatcher to EditText someEdit.addTextChangedListener(TW1); 

TextWatcher personalizado

 public class TextWatcher1 implements TextWatcher { public EditText editText; //constructor public TextWatcher1(EditText et){ super(); editText = et; //Code for monitoring keystrokes editText.setOnKeyListener(new View.OnKeyListener() { @Override public boolean onKey(View v, int keyCode, KeyEvent event) { if(keyCode == KeyEvent.KEYCODE_DEL){ editText.setText(""); } return false; } }); } //Some manipulation with text public void afterTextChanged(Editable s) { if(editText.getText().length() == 12){ editText.setText(editText.getText().delete(editText.getText().length() - 1, editText.getText().length())); editText.setSelection(editText.getText().toString().length()); } if (editText.getText().length()==2||editText.getText().length()==5||editText.getText().length()==8){ editText.setText(editText.getText()+"/"); editText.setSelection(editText.getText().toString().length()); } } public void beforeTextChanged(CharSequence s, int start, int count, int after){ } public void onTextChanged(CharSequence s, int start, int before, int count) { } } 

Mi solución simple que funciona a la perfección. Deberías agregar una bandera. Mi fragmento de código:

 editText.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { if (after < count) { isBackspaceClicked = true; } else { isBackspaceClicked = false; } } @Override public void onTextChanged(CharSequence s, int start, int before, int count) { } @Override public void afterTextChanged(Editable s) { if (!isBackspaceClicked) { // Your current code } else { // Your "backspace" handling } } 

Hay una pregunta similar en Stackoverflow. EditText sobrescribir EditText para obtener acceso al objeto InputConnection que contiene el método deleteSurroundingText . Le ayudará a detectar el evento de eliminación (retroceso). Por favor, eche un vistazo a una solución que proporcioné allí. Android: no puede capturar retroceso / borrar presionar suavemente. teclado

Esto parece estar funcionando para mí:

 public void onTextChanged(CharSequence s, int start, int before, int count) { if (before - count == 1) { onBackSpace(); } else if (s.subSequence(start, start + count).toString().equals("\n")) { onNewLine(); } } 

También me enfrento al mismo problema en Diálogo … porque estoy usando setOnKeyListener. Pero establecí el retorno predeterminado verdadero. Después de cambiar como a continuación el código funciona bien para mí ..

  mDialog.setOnKeyListener(new Dialog.OnKeyListener() { @Override public boolean onKey(DialogInterface arg0, int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK) { mDialog.dismiss(); return true; } return false;//this line is important } }); 

Basado en @Jiff ZanyEditText aquí está WiseEditText con setSoftKeyListener(OnKeyListener)

 package com.locopixel.seagame.ui.custom; import java.util.Random; import android.content.Context; import android.graphics.Color; import android.support.v7.widget.AppCompatEditText; import android.util.AttributeSet; import android.view.KeyEvent; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputConnection; import android.view.inputmethod.InputConnectionWrapper; public class WiseEditText extends AppCompatEditText { private Random r = new Random(); private OnKeyListener keyListener; public WiseEditText(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } public WiseEditText(Context context, AttributeSet attrs) { super(context, attrs); } public WiseEditText(Context context) { super(context); } @Override public InputConnection onCreateInputConnection(EditorInfo outAttrs) { return new MyInputConnection(super.onCreateInputConnection(outAttrs), true); } private class MyInputConnection extends InputConnectionWrapper { public MyInputConnection(InputConnection target, boolean mutable) { super(target, mutable); } @Override public boolean sendKeyEvent(KeyEvent event) { if (keyListener != null) { keyListener.onKey(WiseEditText.this,event.getKeyCode(),event); } return super.sendKeyEvent(event); } @Override public boolean deleteSurroundingText(int beforeLength, int afterLength) { // magic: in latest Android, deleteSurroundingText(1, 0) will be called for backspace if (beforeLength == 1 && afterLength == 0) { // backspace return sendKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL)) && sendKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DEL)); } return super.deleteSurroundingText(beforeLength, afterLength); } } public void setSoftKeyListener(OnKeyListener listener){ keyListener = listener; } } 

Mi problema era que tenía Textwatcher personalizado, así que no quería agregar OnKeyListener a EditText así como tampoco quería crear EditText personalizado. Quería detectar si se presionó retroceso en mi método afterTextChanged , por lo que no debería activar mi evento.

Así es como resolví esto. Espero que sea útil para alguien.

 public class CustomTextWatcher extends AfterTextChangedTextWatcher { private boolean backspacePressed; @Override public void afterTextChanged(Editable s) { if (!backspacePressed) { triggerYourEvent(); } } @Override public void onTextChanged(CharSequence s, int start, int before, int count) { super.onTextChanged(s, start, before, count); backspacePressed = count == 0; //if count == 0, backspace is pressed } } 

He probado @ la solución de Jeff en la versión 4.2, 4.4, 6.0. En 4.2 y 6.0, funciona bien. Pero en 4.4, no funciona.

Encontré una forma fácil de solucionar este problema. El punto clave es insertar un carácter invisible en el contenido de EditText al principio y no permitir que el usuario mueva el cursor antes de este carácter. Mi manera es insertar un personaje de espacio en blanco con un ImageSpan de Zero Width. Aquí está mi código.

  @Override public void afterTextChanged(Editable s) { String ss = s.toString(); if (!ss.startsWith(" ")) { int selection = holder.editText.getSelectionEnd(); s.insert(0, " "); ss = s.toString(); holder.editText.setSelection(selection + 1); } if (ss.startsWith(" ")) { ImageSpan[] spans = s.getSpans(0, 1, ImageSpan.class); if (spans == null || spans.length == 0) { s.setSpan(new ImageSpan(getResources().getDrawable(R.drawable.zero_wdith_drawable)), 0 , 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } } } 

Y necesitamos personalizar un EditText que tenga un SelectionChangeListener

 public class EditTextSelectable extends android.support.v7.widget.AppCompatEditText { public interface OnSelectChangeListener { void onSelectChange(int start, int end); } private OnSelectChangeListener mListener; public void setListener(OnSelectChangeListener listener) { mListener = listener; } ...constructors... @Override protected void onSelectionChanged(int selStart, int selEnd) { if (mListener != null) { mListener.onSelectChange(selStart, selEnd); } super.onSelectionChanged(selStart, selEnd); } 

}

Y el último paso

 holder.editText.setListener(new EditTextSelectable.OnSelectChangeListener() { @Override public void onSelectChange(int start, int end) { if (start == 0 && holder.editText.getText().length() != 0) { holder.editText.setSelection(1, Math.max(1, end)); } } }); 

Y ahora, hemos terminado ~ Podemos detectar el evento clave de retroceso cuando EditText no tiene contenido real, y el usuario no sabrá nada sobre nuestro truco.

Esta pregunta puede ser antigua, pero la respuesta es realmente simple usando un TextWatcher.

 int lastSize=0; @Override public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) { //2. compare the old length of the text with the new one //3. if the length is shorter, then backspace was clicked if (lastSize > charSequence.length()) { //4. Backspace was clicked //5. perform action } //1. get the current length of of the text lastSize = charSequence.length(); } 

Puede establecer un oyente de clave en la actividad y, en el método de callback, puede detectar a qué tecla toca el usuario. El código a continuación es para su referencia. Espero eso ayude.

 //after user hits keys, this method would be called. public boolean onKeyUp(int keyCode, KeyEvent event) { if (editText.isFocused()) { switch (keyCode) { case KeyEvent.KEYCODE_DEL: //delete key Log.i("INFO", "delete key hit"); //you should see this log in ddms after you hit delete key break; } } return super.onKeyUp(keyCode, event); }