Android EditText delete (backspace) key 事件

如何检测 EdText 的 delete (backspace)键事件?我试过使用 TextWatcher,但是当 edit Text 为空时,当我按删除键时,什么也不会发生。我想检测删除键按一个编辑文本,即使它没有文本。

153416 次浏览

注意: onKeyListener不适用于软键盘。

您可以设置 OnKeyListener为您的 editText,以便您可以检测到任何按键
编辑: 一个常见的错误,我们正在检查 KeyEvent.KEYCODE_BACKbackspace,但实际上它是 KeyEvent.KEYCODE_DEL(真的,这个名字是非常混乱!)

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

您可以在活动上设置一个密钥侦听器,并且在回调方法中可以检测 下面的代码供你参考,希望对你有所帮助。

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

你已经很久没问过我了,但我也有同样的问题。正如 Estel 已经提到的,关键侦听器的问题在于它们只能处理硬件键盘。要使用 软键盘完成这项工作,解决方案要更加复杂一些。

我们实际想要重写的一个方法是 EditTextInputConnection类中的 sendKeyEvent。在 IME 中发生键事件时调用此方法。但是为了覆盖这一点,我们需要实现一个自定义的 EditText来覆盖 onCreateInputConnection方法,在代理类中包装默认的 InputConnection对象!:|

听起来很复杂,但这是我能想到的最简单的例子:

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


}


}

调用 setRandomBackgroundColor的那一行是我的特殊退格操作发生的地方。在这种情况下,改变 EditText的背景颜色。

如果您正在从 XML 扩展它,请记住使用完整的包名作为标记:

<cc.buttfu.test.ZanyEditText
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/somefield"
></cc.buttfu.test.ZanyEditText>

这只是对 Idris 的回答的一个补充,同时也增加了对 delete teSuroundingText 的覆盖。我在这里找到了更多信息: Android: WebView/BaseInputConnection 中的 Backspace

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


}


}

使用 TextWatcher 创建 EditText 的示例

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

自定义文本监视器

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) {






}
}

Stackoverflow 中也有类似的问题。您需要重写 EditText以获得对包含 deleteSurroundingText方法的 InputConnection对象的访问。它将帮助您检测删除(退格)事件。请看一下我在那里提供的解决方案 Android-不能在软键盘中捕获退格/删除按钮

我花了两天时间找到了一个解决方案,并且找到了一个有效的方法:)(在软键上)

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) {
}
}

将文本查看器添加到 EditText 之后:

yourEditText.addTextChangedListener(textWatcher);

我希望它也适用于其他 Android 设备(三星、 LG 等)。

以下是我的简单解决方案,适用于所有 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 ...


}
}

更新17.04.18
正如注释中指出的那样,如果 EditText 为空,这个解决方案不会跟踪回退按钮(与大多数其他解决方案相同)。
然而,对于大多数用例来说,这已经足够了。
附注: 如果今天我必须创造一些类似的东西,我会这样做:

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());
}
}

那就把它当成一个普通的文本观察者:

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

这似乎对我有效:

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();
}
}

我在对话中也遇到了同样的问题。.因为我正在使用 setOnKeyListener。.但我将 default return 设置为 true。改变后喜欢下面的代码它工作的很好为我。.

    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


}
});

基于@Jiff ZanyEditText这里是 WiseEditTextsetSoftKeyListener(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;
}


}

我的问题是,我有自定义的 Textwatcher,所以我不想添加 OnKeyListenerEditText,以及我不想创建自定义的 EditText。我想检测在 afterTextChanged方法中是否按下了退格键,所以我不应该触发事件。

我就是这么解决的,希望对谁有帮助。

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

我已经在4.2,4.4,6.0版本上测试了@Jeff 的解决方案。在4.2和6.0上,它运行良好。但是在4.4上,它不工作。

我找到了一个解决这个问题的简单方法。关键是在 EditText 的开始部分插入一个不可见的字符,并且不要让用户在这个字符之前移动光标。我的方法是插入一个空白字符,其上包含一个 ImageSpan 为零宽度的字符。这是我的密码。

                @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);
}
}
}

我们需要一个定制的 EditText,它有一个 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);
}

}

最后一步

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

现在,我们完成了 ~ 我们可以检测回退键事件时,EditText 没有实际的内容,用户将不知道我们的技巧。

这个问题可能很老,但是使用 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();
}

我的简单解决方案,非常好用。你应该添加一个标志。我的代码片段:

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

对于一个利用 Kotlin 的人来说

addOnTextChanged 不够灵活处理一些情况(例如: 检测当编辑文本为空时用户是否按删除键)

setOnkeyListener甚至工作软键盘或硬键盘!但是 只是在一些设备上。就我而言,它可以在三星 s8上运行,但不能在小米 mi8 se 上运行。

如果您使用 kotlin,您可以使用交叉线函数 doOnTextChanged,它与 addOnTextChanged相同,但回调被触发,即使编辑文本为空。

注意: doOnTextChanged 是 Android KTX 库的一部分

我已经找到了一个非常简单的解决方案,使用软键盘。

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

虽然有些迟,但是它可以帮助新的访问者,使用 TextWatcher()代替将会有很大的帮助,而且它也可以同时适用于软键盘和硬键盘。

 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 (charSequence.length() > 0) {
//Here it means back button is pressed and edit text is now empty
} else {
//Here edit text has some text
}
}


@Override
public void afterTextChanged(Editable editable) {
}
});