Android EditText删除(退格)键事件

时间:2011-02-03 13:45:12

标签: android events android-edittext key

如何检测editText的删除(退格)键事件?我尝试过使用TextWatcher,但是当editText为空时,当我按下删除键时,没有任何反应。即使没有文本,我想检测删除键按下一个editText。

18 个答案:

答案 0 :(得分:134)

注意: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;       
    }
});

答案 1 :(得分:81)

你提问已经有一段时间,但我遇到了同样的问题。正如Estel已经提到的那样,关键监听器的问题在于它们只能与硬件键盘配合使用。要使用 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>

答案 2 :(得分:62)

这只是Idris答案的补充,也是对overrideSurroundingText的覆盖。我在这里找到了更多相关信息:Android: Backspace in 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 :(得分:23)

这是我的简单解决方案,适用于所有API:

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

更新17.04.18
正如评论中所指出的,如果EditText为空,此解决方案不会跟踪退格键(与大多数其他解决方案相同)。
但是,对于大多数用例来说,这已经足够了 的 P.S。如果我今天必须创建类似的东西,我会这样做:

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

然后将其用作常规TextWatcher:

<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" type="text/css" href="http://fonts.googleapis.com/css?family=Ubuntu:regular,bold&subset=Latin">
<style>body { font-family: Ubuntu, sans-serif; }</style>
</head>
<body>

<canvas style="border-radius: 100px;" id="myCanvas" width="200" height="200">
Your browser does not support the HTML5 canvas tag.</canvas>

<script>

function getParameterByName(name, url) {
    if (!url) url = window.location.href;
    name = name.replace(/[\[\]]/g, "\\$&");
    var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"),
        results = regex.exec(url);
    if (!results) return null;
    if (!results[2]) return '';
    return decodeURIComponent(results[2].replace(/\+/g, " "));
}

var size = 200
var textSize=size * 0.55;
var countryCode = "nl";
var text = "123";

var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");

var img = new Image;
img.onload = function(){
  ctx.drawImage(img,-1,-1,size,size); // removes the 1px border the flags sometimes have
  ctx.font = textSize+"px Ubuntu";
  ctx.textAlign="center";
  ctx.fillStyle = "#260C4D";
  ctx.fillText(text,size/2,size/2 + textSize / 2.85);
};
img.src = "http://www.geonames.org/flags/x/"+countryCode+".gif";
</script>

</body>
</html>

答案 4 :(得分:12)

我发送了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设备(三星,LG等)。

答案 5 :(得分: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) {



        }
    }

答案 6 :(得分:1)

我的简单解决方案完美无缺。你应该添加一个标志。我的代码片段:

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

答案 7 :(得分:0)

我在Dialog中也面临同样的问题..因为我使用的是setOnKeyListener ..但我设置默认返回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 

        }
    });

答案 8 :(得分:0)

姗姗来迟,但它可能对新访问者有所帮助,改用 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) {
            }
        });

答案 9 :(得分: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
        }
    }
}

答案 10 :(得分:0)

用于某些使用Kotlin的人

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

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

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

答案 11 :(得分:0)

这个问题可能很旧,但使用TextWatcher答案非常简单。

{{1}}

答案 12 :(得分: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没有实际内容时,我们可以检测到退格键事件,用户对我们的技巧一无所知。

答案 13 :(得分:0)

我的问题是,我有自定义OnKeyListener,因此我不想将EditText添加到EditText以及我不想创建自定义{{} 1}}。我想检测我的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
}
}

答案 14 :(得分:0)

基于@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;
    }

}

答案 15 :(得分:0)

这似乎对我有用:

GridView

答案 16 :(得分:0)

Stackoverflow中有类似的问题。您需要覆盖EditText才能访问包含InputConnection方法的deleteSurroundingText对象。它将帮助您检测删除(退格)事件。请看一下我在那里提供的解决方案Android - cannot capture backspace/delete press in soft. keyboard

答案 17 :(得分:-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);
    }