Comment détecter un événement de clé delete (backspace) pour un editText? J'ai essayé d'utiliser TextWatcher, mais quand editText est vide, lorsque j'appuie sur la touche Suppr, rien ne se produit. Je veux détecter une touche de suppression, appuyez sur un texte d'édition même s'il ne contient pas de texte.
REMARQUE: onKeyListener
ne fonctionne pas pour les claviers logiciels.
Vous pouvez définir OnKeyListener
pour vous editText
afin de détecter toute pression sur une touche.
EDIT: Une erreur commune: nous vérifions KeyEvent.KEYCODE_BACK
pour backspace
, mais c’est vraiment KeyEvent.KEYCODE_DEL
(ce nom est vraiment déroutant!)
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;
}
});
Cela fait un moment que vous avez demandé, mais je viens d'avoir le même problème. Comme mentionné par Estel, le problème des écouteurs clés est qu'ils ne fonctionnent qu'avec des claviers matériels. Pour ce faire avec un IME (clavier logiciel) , la solution est un peu plus élaborée.
La seule méthode que nous voulons réellement remplacer est sendKeyEvent
dans la classe EditText
's InputConnection
. Cette méthode est appelée lorsque des événements clés se produisent dans un IME. Mais pour redéfinir cela, nous devons implémenter un EditText
personnalisé, qui redéfinit la méthode onCreateInputConnection
, encapsulant l'objet InputConnection
par défaut dans une classe proxy! : |
Cela semble compliqué, mais voici l'exemple le plus simple que j'ai pu inventer:
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 ligne avec l'appel à setRandomBackgroundColor
est l'endroit où se produit mon action spéciale de retour arrière. Dans ce cas, changez la couleur d'arrière-plan de la EditText
.
Si vous gonflez cela à partir de XML, n'oubliez pas d'utiliser le nom complet du package en tant que balise:
<cc.buttfu.test.ZanyEditText
Android:layout_width="fill_parent"
Android:layout_height="wrap_content"
Android:id="@+id/somefield"
></cc.buttfu.test.ZanyEditText>
Ceci est juste un ajout à la réponse d'Idris, ajoutant également le remplacement à deleteSurroundingText. J'ai trouvé plus d'informations à ce sujet ici: Android: Retour arrière dans 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);
}
}
}
Voici ma solution simple, qui fonctionne pour toutes les 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 ...
}
}
MISE À JOUR 17.04.18 .
Comme indiqué dans les commentaires, cette solution ne détecte pas la pression de retour arrière si EditText est vide (comme dans la plupart des autres solutions).
Cependant, cela suffit pour la plupart des cas d'utilisation.
P.S. Si je devais créer quelque chose de similaire aujourd'hui, je ferais:
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());
}
}
Ensuite, utilisez-le simplement comme TextWatcher ordinaire:
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
}
});
J'ai envoyé 2 jours pour trouver une solution et j'en ai trouvé une qui fonctionnait :)
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) {
}
}
Après avoir ajouté le textwatcher à votre EditText:
yourEditText.addTextChangedListener(textWatcher);
J'espère que cela fonctionne aussi sur d'autres appareils Android (Samsung, LG, etc.).
Exemple de création EditText avec 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 personnalisé
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) {
}
}
Ma solution simple qui fonctionne parfaitement. Vous devriez ajouter un drapeau. Mon extrait de code:
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
}
}
J'ai testé la solution de @ Jeff sur les versions 4.2, 4.4, 6.0. Sur 4.2 et 6.0, cela fonctionne bien. Mais sur 4.4, ça ne marche pas.
J'ai trouvé un moyen facile de contourner ce problème. Le point clé est d'insérer un caractère invisible dans le contenu de EditText au début et de ne pas laisser l'utilisateur déplacer le curseur avant ce caractère. Mon moyen est d'insérer un caractère d'espace blanc avec un ImageSpan de largeur nulle. Voici mon code.
@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);
}
}
}
Et nous avons besoin d'un EditText personnalisé avec 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);
}
}
Et la dernière étape
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));
}
}
});
Et maintenant, nous avons terminé ~ Nous pouvons détecter un événement de touche de retour arrière quand EditText n'a pas de contenu réel, et l'utilisateur ne saura rien de notre astuce.
pour quelqu'un qui utilise Kotlin
addOnTextChanged
n'est pas assez flexible pour traiter certains cas (par exemple, détecter si l'utilisateur appuie sur Supprimer lorsque le texte modifié était vide)
setOnkeyListener
a même travaillé clavier, clavier ou clavier dur! mais seulement sur certains appareils. Dans mon cas, cela fonctionne sur Samsung s8 mais pas sur Xiaomi mi8 se.
si vous utilisez kotlin, vous pouvez utiliser la fonction de reliure doOnTextChanged
, identique à addOnTextChanged
mais le rappel est déclenché même si le texte de montage était vide.
Je suis également confronté au même problème dans Dialog .. parce que j'utilise setOnKeyListener .. Mais j'ai défini default return true. Après le changement, comme ci-dessous, le code fonctionne bien pour moi.
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
}
});
Basé sur @Jiff ZanyEditText
, voici WiseEditText
avec 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;
}
}
Cette question est peut-être ancienne, mais la réponse est très simple avec 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();
}
Cela semble fonctionner pour moi:
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();
}
}
Il y a une question similaire dans le Stackoverflow. Vous devez remplacer EditText
pour avoir accès à l'objet InputConnection
qui contient la méthode deleteSurroundingText
. Cela vous aidera à détecter un événement de suppression (retour arrière). S'il vous plaît, jetez un oeil à une solution que j'ai fourni là-bas Android - ne peut pas capturer de retour arrière/supprimer la presse au soft clavier
Mon problème était que j'avais Textwatcher
personnalisé, alors je ne voulais pas ajouter OnKeyListener
à EditText
et je ne voulais pas créer de EditText
personnalisé. Je voulais détecter si le retour arrière a été activé dans ma méthode afterTextChanged
. Je ne devrais donc pas déclencher mon événement.
C'est comme ça que j'ai résolu ça. J'espère que ce serait utile pour quelqu'un.
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
}
}
J'ai trouvé une solution très simple qui fonctionne avec un clavier logiciel.
override fun onTextChanged(text: CharSequence?, start: Int, before: Int, count: Int) {
text?.let {
if(count < before) {
Toast.makeText(context, "backspace pressed", Toast.LENGTH_SHORT).show()
// implement your own code
}
}
}