Событие KeyTime delete (backspace)

Как определить событие ключа delete (backspace) для editText? Я пробовал использовать TextWatcher, но когда editText пуст, когда я нажимаю клавишу "Удалить", ничего не происходит. Я хочу обнаружить кнопку удаления, нажав foe на editText, даже если у него нет текста.

Ответ 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);
    }