Android EditText delete(backspace)键事件


Answers:


172

注意:onKeyListener不适用于软键盘。

你可以设置OnKeyListenereditText这样你就可以检测到任何按键
编辑:我们正在检查一个常见的错误KeyEvent.KEYCODE_BACKbackspace,但实际上它是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;       
    }
});

9
我只是尝试过,但是onKeyListeners显然没有注册退格键。
Stefs 2011年

3
它不适用于软键盘。这仅适用于硬件输入。
Varundroid 2014年

6
在我的Nexus4(运行中的KitKat)上,此功能适用于软件键盘。
Matthias 2014年

10
所以,如果它不能用于软键,那么为什么在Android平台中/在此平台下接受此答案
。– DJphy 2015年

32
event.getAction() == KeyEvent.ACTION_DOWN && event.getKeyCode() == KeyEvent.KEYCODE_DEL如果您不希望每次按下退格键两次触发事件,则使用
Fonix

83

自从您问了已经有一段时间了,但是我也遇到了同样的问题。正如Estel已经提到的那样,按键侦听器的问题在于它们只能与硬件键盘一起使用。要使用IME(软键盘)执行此操作,解决方案会更加复杂。

我们实际要覆盖的单个方法sendKeyEventEditTextInputConnection类中。当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>

27
我最近在果冻豆上遇到了同样的问题。我发现此解决方案最有效,除了我必须重写deleteSurroundingText(...)而不是sendKeyEvent(...)(根本没有调用)。希望这对别人有帮助!
布兰登2012年

这个答案,加上上面的@Brandon评论,为我工作了。我现在想知道的是,它将如何在JellyBean之前的设备上运行。
Christopher Perry

对于我来说,它确实可以在2.2和2.3设备上使用公认的答案。
Christoph

似乎在2.3上触发了两次退格键事件::/
Jeff

25
当edittext为空时,这不起作用,有关edittext为空且没有文本时如何获取删除键事件的任何想法?4.2
Rickster 2014年

69

这只是对Idris答案的补充,同时也将覆盖添加到deleteSurroundingText中。我在这里找到了更多信息:Android: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);
        }

    }

}

3
谢谢!该deleteSurroundingText位正是我需要什么努力无数其他的解决方案之后。
亚当·罗森菲尔德

5
这个解决方案在我以前的Android版本上确实非常有效,但是不幸的是,deleteSurroundingText仅在删除4.4(KitKat)上的空白时才调用。我已经在Nexus4和Nexus 7上进行了测试。–
Dean

1
当EditText为多行时,似乎需要deleteSurroundingText。怪异
Alex Sorokoletov 2014年

7
非常感谢,没有deleteDurroundText不能使用。Android非常随机,他们应该将其重命名为androm。
Torsten Ojaperv

2
它对我有用,但是我再也不能删除标点符号或空格了!
jaytj95 '16

29

这是我简单的解决方案,适用于所有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 
        }
    });

正是我所需要的!谢谢!
DH28 '16

9
TextWatcher不会在空的EditText上触发
Dan Neacșu

@Leo Droidcoder我在类似的解决方案中使用过。清晰,简洁且效果完美...欢呼。
AJW

此算法有一个缺陷,好像您在键入内容后单击空格,然后以前的长度大于s.length
Marcin S.

2
只要您不使用选择(自动
补全

13

我花了两天时间找到解决方案,然后找到了一个可行的解决方案:)(在软键上)

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设备(三星,LG等)上使用。


设备HTC需求(尽管HTC很常见:-P)
Junaid

如果键入的是空格,则也计数== 0
Bincy Baby

辉煌的第一答案兄弟:)
Gundu Bandgar

6
那完全行不通。仅当edittext为空时,count == 0才是!
Leo Droidcoder

@MarcAlexander我不确定这个答案,但是您可以在上面的答案中检查我的解决方案
Leo Droidcoder

5

我的简单解决方案非常有效。您应该添加一个标志。我的代码段:

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
            }
        }

textChangeListner从未在emptTextview上调用。
Janardhan R

3

使用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);

自定义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) {



        }
    }

1

给一些使用Kotlin的人

addOnTextChanged 不够灵活,无法处理某些情况(例如:检测用户在编辑文本为空时是否按Delete键)

setOnkeyListener甚至可以使用软键盘或硬键盘!但仅在某些设备上。就我而言,它适用于三星s8,但不适用于小米mi8 se。

如果您使用kotlin,则可以使用crossline函数doOnTextChanged,该功能与crossline函数相同,addOnTextChanged但是即使编辑文本为空,也会触发回调。

注意:doOnTextChanged是Android KTX库的一部分


2
您可能会指定doOnTextChanged 可在Android KTX库中访问扩展功能
石头

2
但似乎回调不是“触发的,即使编辑文本为空”。您能否提供一些空的delete(backspace)拦截代码段EditText?在此先感谢
石头

1
啊,我在开发项目时已经对其进行了测试。在我的情况下是在小米mi8se上,当edittext为空并且您按Delete时,没有触发回调。我将搜索此句子的摘录。
农德孟黄长发晃


0

这似乎为我工作:

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();
    }
}

0

我在Dialog中也遇到相同的问题。因为我使用的是setOnKeyListener。但是我将default设置为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 

        }
    });

0

基于@Jiff ZanyEditText这里是WiseEditTextsetSoftKeyListener(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;
    }

}

每个删除键事件均被调用两次。
Pankaj Kumar

0

我的问题是,我有custom Textwatcher,所以我不想添加OnKeyListenerEditText,也不想创建custom 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
}
}

0

我已经在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没有实际内容时,我们可以检测到退格键事件,并且用户对我们的技巧一无所知。


0

这个问题可能很老,但是使用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();
}

与以前的解决方案非常相似,这可以由自动完成/建议触发。
Stonz2

0

我发现了一个非常简单的解决方案,可以与软键盘配合使用。

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
        }
    }
}

-3

您可以在活动上设置一个键侦听器,并在回调方法中,您可以检测到用户按下了哪个键。以下代码供您参考。希望能帮助到你。

//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);
    }

选中了此解决方案-KEYCODE_DEL仅在编辑文本无法自行处理的情况下才会投入使用。例如,当editText中没有文本,或者某些文本,但是光标刚开始时。有趣的是,就我而言,我确实需要这种行为
Anton Kizema

在我的活动中,没有EditText,我只是以编程方式使键盘出现。我需要抓住每个软键盘键,这似乎是唯一可行的解​​决方案。另一个是重写dispatchKeyEvent方法。不幸的是,从JellyBean开始,IME不会发送DELETE键的KeyEvent。 developer.android.com/reference/android/view/KeyEvent.html
Bemipefe
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.