Android EditText удалить (backspace) ключевое событие
Как я могу обнаружить ключевое событие delete (backspace) для editText? Я пробовал использовать TextWatcher, но когда editText пуст, когда я нажимаю клавишу delete, ничего не происходит. Я хочу обнаружить, что клавиша delete нажимает на editText, даже если у него нет текста.
15 ответов:
Примечание:
onKeyListener
не работает для мягких клавиатур.вы можете установить
OnKeyListener
для васeditText
таким образом, вы можете обнаружить любое нажатие клавиши
EDIT: распространенная ошибка, которую мы проверяем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; } });
прошло некоторое время с тех пор, как вы спросили, но у меня была та же проблема. Как уже упоминалось Estel проблема с ключевыми слушателями заключается в том, что они работают только с аппаратными клавиатурами. Чтобы сделать это с помощью IME (мягкая клавиатура), решение немного более сложное.
единственный метод, который мы действительно хотим переопределить, это
sendKeyEvent
наEditText
' sInputConnection
класса. Этот метод вызывается, когда ключевые события происходят в 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
где происходит мое специальное действие backspace. В этом случае изменение 'ы фона.если вы раздуваете это из 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); } } }
вот мое простое решение, которое работает для всех 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 пуст (так же, как и большинство других решений).
Однако, этого достаточно для большинства случаев использования.
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 } });
Я отправил 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);
Я надеюсь, что он работает и на других устройствах android (samsung, LG и т. д.).
пример создания 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) { } }
мое простое решение, которое отлично работает. Вы должны добавить флаг. Мой фрагмент кода:
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 } }
Это, кажется, работает для меня :
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.. Но я установил значение по умолчанию 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
. Я хотел обнаружить, если клавиша была нажата в моем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 key, когда 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(); }
вы можете установить ключевой прослушиватель для действия, а в методе обратного вызова вы можете обнаружить какой ключ пользователь нажал. Код ниже для вашей справки. Надеюсь, это поможет.
//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); }