Как я могу обнаружить ключевое событие delete (backspace) для editText? Я пробовал использовать TextWatcher, но когда editText пуст, когда я нажимаю клавишу удаления, ничего не происходит. Я хочу обнаружить нажатие клавиши удаления для editText, даже если в нем нет текста.
Android EditText удалить (backspace) ключевое событие
Ответы (18)
ПРИМЕЧАНИЕ. 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
, если вы не хотите, чтобы событие запускалось дважды при нажатии клавиши Backspace
- person Fonix; 15.08.2016
Прошло некоторое время с тех пор, как вы спросили, но у меня была такая же проблема. Как уже упоминала Эстель, проблема с ключевыми слушателями в том, что они работают только с аппаратными клавиатурами. Чтобы сделать это с помощью IME (программной клавиатуры), решение немного сложнее.
Единственный метод, который мы действительно хотим переопределить, - это sendKeyEvent
в InputConnection
классе EditText
. Этот метод вызывается, когда ключевые события происходят в 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>
Это просто дополнение к ответу Идриса, добавляющее также переопределение для 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);
}
}
}
deleteSurroundingText
был именно тем, что мне было нужно после того, как я испробовал множество других решений.
- person Adam Rosenfield; 17.09.2013
if (beforeLength == 1 && afterLength == 0 && ZanyEditText.this.getText().length() == 0) {
- person Cheok Yan Cheng; 17.09.2018
Вот мое простое решение, которое работает для всех 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.
Как указано в комментариях, это решение не отслеживает нажатие клавиши Backspace, если 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
}
});
Отправил 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 и т. Д.).
Мое простое решение, которое отлично работает. Вы должны добавить флаг. Мой фрагмент кода:
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
}
}
Пример создания 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) {
}
}
Я нашел действительно простое решение, которое работает с мягкой клавиатурой.
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
}
}
}
для тех, кто использует Kotlin
addOnTextChanged
недостаточно гибок для обработки некоторых случаев (например, определение того, нажимает ли пользователь кнопку удаления, когда текст редактирования был пуст)
setOnkeyListener
Работала даже мягкая клавиатура или жесткая клавиатура! но только на некоторых устройствах. В моем случае он работает на Samsung s8, но не работает на Xiaomi mi8 se.
если вы используете kotlin, вы можете использовать функцию кросслайна doOnTextChanged
, она такая же, как addOnTextChanged
, но срабатывает обратный вызов, даже если текст редактирования был пуст.
ПРИМЕЧАНИЕ. DoOnTextChanged является частью библиотеки Android KTX.
doOnTextChanged
доступна в библиотеке Android KTX
- person stone; 17.12.2019
EditText
? заранее спасибо
- person stone; 17.12.2019
В Stackoverflow есть аналогичный вопрос. Вам необходимо переопределить EditText
, чтобы получить доступ к объекту InputConnection
, который содержит метод deleteSurroundingText
. Это поможет вам обнаружить событие удаления (возврата). Пожалуйста, взгляните на решение, которое я предоставил там Android - не может захватывать backspace / delete press в программном обеспечении. клавиатура
Кажется, это работает для меня:
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();
}
}
Я также столкнулся с такой же проблемой в Dialog .. потому что я использую setOnKeyListener .. Но я установил значение 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
вот 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;
}
}
Моя проблема заключалась в том, что у меня был собственный 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
}
}
Я тестировал решение @ Jeff на версиях 4.2, 4.4, 6.0. На 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));
}
}
});
И теперь мы закончили. Мы можем обнаружить событие клавиши Backspace, когда 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();
}
Запоздало, но это может помочь новым посетителям, вместо этого используйте 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) {
}
});
Вы можете установить ключевой прослушиватель для действия, а в методе обратного вызова вы можете определить, какой ключ нажимает пользователь. Код ниже предназначен для справки. Надеюсь, поможет.
//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);
}