【发布时间】:2011-06-20 16:29:44
【问题描述】:
如何检测 editText 的删除(退格)键事件?我试过使用TextWatcher,但是当editText为空时,当我按下delete键时,什么也没有发生。即使没有文本,我也想检测删除键的敌人editText。
【问题讨论】:
标签: android events android-edittext key
如何检测 editText 的删除(退格)键事件?我试过使用TextWatcher,但是当editText为空时,当我按下delete键时,什么也没有发生。即使没有文本,我也想检测删除键的敌人editText。
【问题讨论】:
标签: android events android-edittext key
迟到了,但它可能对新访问者有所帮助,改用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) {
}
});
【讨论】:
对于使用 Kotlin 的人
addOnTextChanged 不够灵活无法处理某些情况(例如:当编辑文本为空时检测用户是否按下删除键)
setOnkeyListener 甚至可以使用软键盘或硬键盘!但仅在某些设备上。就我而言,它适用于三星 s8,但不适用于小米 mi8 se。
如果你使用kotlin,你可以使用crossline函数doOnTextChanged,它与addOnTextChanged相同,但即使编辑文本为空也会触发回调。
注意:doOnTextChanged 是Android KTX library 的一部分
【讨论】:
doOnTextChanged 扩展函数可在Android KTX 库中访问
EditText 提供一些带有删除(退格)拦截的sn-p?提前致谢
我找到了一个非常简单的解决方案,它适用于软键盘。
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
}
}
}
【讨论】:
我的简单解决方案完美运行。您应该添加一个标志。我的代码sn-p:
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
}
}
【讨论】:
注意:onKeyListener 不适用于软键盘。
您可以为您设置OnKeyListener editText,以便您可以检测到任何按键
编辑:我们检查KeyEvent.KEYCODE_BACK 时的一个常见错误backspace,但实际上是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;
}
});
【讨论】:
event.getAction() == KeyEvent.ACTION_DOWN && event.getKeyCode() == KeyEvent.KEYCODE_DEL
这是我的简单解决方案,适用于所有 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 .
正如 cmets 中所指出的,如果 EditText 为空(与大多数其他解决方案相同),此解决方案不会跟踪退格键。
但是,对于大多数用例来说,这已经足够了。
P.S.如果我今天必须创造类似的东西,我会这样做:
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());
}
}
然后将其用作常规 TextWatcher:
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
}
});
【讨论】:
这个问题可能很老,但答案很简单,使用 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();
}
【讨论】:
我已经在 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);
}
}
}
我们需要自定义一个具有 SelectionChangeListener 的 EditText
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,所以我不想将OnKeyListener 添加到EditText,也不想创建自定义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
}
}
【讨论】:
基于@Jiff ZanyEditText 这里是WiseEditText 和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;
}
}
【讨论】:
我在 Dialog 中也遇到了同样的问题。因为我正在使用 setOnKeyListener 。但我设置了默认返回 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
}
});
【讨论】:
这似乎对我有用:
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();
}
}
【讨论】:
我花了 2 天时间寻找解决方案,我找到了一个可行的解决方案 :)(在软键上)
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) {
}
}
将 textwatcher 添加到您的 EditText 后:
yourEditText.addTextChangedListener(textWatcher);
我希望它也适用于其他安卓设备(三星、LG 等)。
【讨论】:
Stackoverflow 中有一个类似的问题。您需要覆盖EditText 才能访问包含deleteSurroundingText 方法的InputConnection 对象。它将帮助您检测删除(退格)事件。请看看我在那里提供的解决方案Android - cannot capture backspace/delete press in soft. keyboard
【讨论】:
使用 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) {
}
}
【讨论】:
这只是对 Idris 答案的补充,还添加了对 deleteSurroundingText 的覆盖。我在这里找到了更多信息:Android: Backspace in 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);
}
}
}
【讨论】:
deleteSurroundingText 位正是我所需要的。
你可以在activity上设置一个key listener,在回调方法中,你可以检测到 用户按了哪个键。下面的代码供您参考。希望对您有所帮助。
//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 已经提到的,按键监听器的问题是它们只能使用硬件键盘。要使用 IME(软键盘),解决方案要复杂一些。
我们真正想要重写的单个方法是EditText 的InputConnection 类中的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>
【讨论】: