Как определить событие ключа delete (backspace) для editText? Я пробовал использовать TextWatcher, но когда editText пуст, когда я нажимаю клавишу "Удалить", ничего не происходит. Я хочу обнаружить кнопку удаления, нажав foe на editText, даже если у него нет текста.
Событие KeyTime delete (backspace)
Ответ 1
ПРИМЕЧАНИЕ: 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;
}
});
Ответ 2
Прошло некоторое время с тех пор, как вы спросили, но у меня была такая же проблема. Как уже упоминалось Эстелем, проблема с ключевыми слушателями заключается в том, что они работают только с аппаратными клавиатурами. Чтобы сделать это с помощью IME (мягкая клавиатура), решение немного сложнее.
Единственный метод, который мы действительно хотим переопределить, - это sendKeyEvent
в классе EditText
InputConnection
. Этот метод вызывается, когда ключевые события происходят в 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>
Ответ 3
Это просто дополнение к ответу Идриса, добавление в дополнение к deleteSurroundingText. Я нашел дополнительную информацию об этом здесь: Android: Backspace в 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);
}
}
}
Ответ 4
Вот мое простое решение, которое работает для всех 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 пуст (так же, как и большинство других решений).
Тем не менее, этого достаточно для большинства случаев использования.
PS Если бы мне пришлось сегодня создать нечто подобное, я бы сделал:
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
}
});
Ответ 5
Я отправил 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) {
}
}
После добавления текстового элемента в ваш EditText:
yourEditText.addTextChangedListener(textWatcher);
Я надеюсь, что он будет работать и на других устройствах Android (samsung, LG и т.д.).
Ответ 6
Пример создания EditText с 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
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) {
}
}
Ответ 7
Мое простое решение, которое работает отлично. Вы должны добавить флаг. Мой фрагмент кода:
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
}
}
Ответ 8
В Stackoverflow есть аналогичный вопрос. Вам необходимо переопределить EditText
, чтобы получить доступ к объекту InputConnection
, который содержит метод deleteSurroundingText
. Это поможет вам обнаружить событие удаления (backspace). Пожалуйста, взгляните на решение, которое я предоставил там Android - не удается захватить обратное/удаление, нажав в мягком режиме. Клавиатура
Ответ 9
Кажется, это работает для меня:
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();
}
}
Ответ 10
Я также сталкиваюсь с той же проблемой в Dialog.. потому что я использую 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
}
});
Ответ 11
На основе @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;
}
}
Ответ 12
Моя проблема заключалась в том, что у меня был пользовательский Textwatcher
, поэтому я не хотел добавлять OnKeyListener
в EditText
, а также не хотел создавать пользовательские EditText
. Я хотел бы определить, было ли нажато backspace в моем методе 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
}
}
Ответ 13
Я тестировал решение @Jeff на версии 4.2, 4.4, 6.0. В 4.2 и 6.0 он работает хорошо. Но в 4.4 он не работает.
Я нашел простой способ обойти эту проблему. Ключевым моментом является вставка невидимого символа в содержимое EditText в начале и не позволять пользователю перемещать курсор перед этим символом. Мой способ - вставить символ пробела с ImageSpan Zero Width на нем. Вот мой код.
@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));
}
}
});
И теперь, мы закончили ~ Мы можем обнаружить событие ключевого слова backspace, когда EditText не имеет фактического контента, и пользователь ничего не узнает о нашем трюке.
Ответ 14
Этот вопрос может быть старым, но ответ действительно прост с помощью 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();
}
Ответ 15
для кого-то, кто использует Kotlin
addOnTextChanged
не достаточно гибок для обработки некоторых случаев (например: определить, addOnTextChanged
ли пользователь кнопку удаления, когда текст редактирования был пустым)
setOnkeyListener
работал даже на мягкой клавиатуре или жесткой клавиатуре! но только на некоторых устройствах. В моем случае это работает на Samsung s8, но не работает на Xiaomi mi8 se.
если вы используете kotlin, вы можете использовать doOnTextChanged
функцию doOnTextChanged
, она так же, как addOnTextChanged
но обратный вызов срабатывает, даже если редактирование текста было пустым.
Ответ 16
Я нашел действительно простое решение, которое работает с мягкой клавиатурой.
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
}
}
}
Ответ 17
Вы можете установить прослушиватель клавиш для активности, а в методе обратного вызова вы можете обнаружить который нажимает на пользователя. Код ниже приведен для вашей справки. Надеюсь, что это поможет.
//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);
}