【问题标题】:Android EditText delete(backspace) key eventAndroid EditText 删除(退格)键事件
【发布时间】:2011-06-20 16:29:44
【问题描述】:

如何检测 editText 的删除(退格)键事件?我试过使用TextWatcher,但是当editText为空时,当我按下delete键时,什么也没有发生。即使没有文本,我也想检测删除键的敌人editText。

【问题讨论】:

    标签: android events android-edittext key


    【解决方案1】:

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

    【讨论】:

      【解决方案2】:

      对于使用 Kotlin 的人

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

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

      如果你使用kotlin,你可以使用crossline函数doOnTextChanged,它与addOnTextChanged相同,但即使编辑文本为空也会触发回调。

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

      【讨论】:

      • 您可能会指定doOnTextChanged 扩展函数可在Android KTX 库中访问
      • 但似乎回调不是“即使编辑文本为空也被触发”。您能否为空EditText 提供一些带有删除(退格)拦截的sn-p?提前致谢
      • 啊,我开发项目的时候已经测试过了。就我而言,在小米 mi8se 上,当 edittext 为空并且您按删除时,没有触发回调。我会为这句话搜索sn-p。
      【解决方案3】:

      我找到了一个非常简单的解决方案,它适用于软键盘。

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

      【讨论】:

      • 用户实际上可以粘贴短 1 个字符的文本,这将显示
      【解决方案4】:

      我的简单解决方案完美运行。您应该添加一个标志。我的代码sn-p:

      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。
      【解决方案5】:

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

      【讨论】:

      • 我刚试过,但 onKeyListeners 显然没有注册退格键。
      • 它不适用于软键盘。这仅适用于硬件输入。
      • 在我的 Nexus4(运行股票 KitKat)上,这确实适用于软键盘。
      • SO 如果它不适用于软键,那么为什么这个答案在 android 平台中/下被接受..
      • 如果您不想每次按退格键触发两次事件,请使用 event.getAction() == KeyEvent.ACTION_DOWN &amp;&amp; event.getKeyCode() == KeyEvent.KEYCODE_DEL
      【解决方案6】:

      这是我的简单解决方案,适用于所有 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 .
      正如 cmets 中所指出的,如果 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 
              }
          });
      

      【讨论】:

      • TextWatcher 不会在空的 EditText 上触发
      • 这个算法有一个缺陷,好像你在输入后点击空格然后之前的长度大于s.length
      • 只要你不使用选择(自动完成)就可以工作
      • 如果您选择自动完成建议,这将被触发
      【解决方案7】:

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

      【讨论】:

      • 很像以前的解决方案,这可以通过自动完成/建议来触发。
      【解决方案8】:

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

      【讨论】:

        【解决方案9】:

        我的问题是,我有自定义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
        }
        }
        

        【讨论】:

          【解决方案10】:

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

          【讨论】:

          • 每个删除键事件都会被调用两次。
          【解决方案11】:

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

          【讨论】:

            【解决方案12】:

            这似乎对我有用:

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

            【讨论】:

              【解决方案13】:

              我花了 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);
              

              我希望它也适用于其他安卓设备(三星、LG 等)。

              【讨论】:

              • 设备 HTC 的愿望(虽然 HTC 很常见:-P)
              • 如果输入的是空格,那么也计数 == 0
              • 那完全行不通。 count == 0 只有在edittext为空时才会出现!
              • @MarcAlexander 我不确定这个答案,但是您可以在上面的答案中查看我的解决方案
              【解决方案14】:

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

              【讨论】:

                【解决方案15】:

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

                自定义文本观察器

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

                【讨论】:

                  【解决方案16】:

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

                  【讨论】:

                  • 谢谢!在尝试了无数其他解决方案后,deleteSurroundingText 位正是我所需要的。
                  • 这个解决方案在以前的 Android 版本上对我来说非常有效,但不幸的是 deleteSurroundingText 仅在 4.4(KitKat) 上删除空格时才被调用。我已经在 Nexus4 和 7 上进行了测试。
                  • EditText 为多行时,似乎需要 deleteSurroundingText。奇怪
                  • 非常感谢,没有 deleteSurroundText。 Android 是如此随机,以至于他们应该将其重命名为 androm。
                  • 它对我有用,但我不能再删除标点符号或空格了!
                  【解决方案17】:

                  你可以在activity上设置一个key listener,在回调方法中,你可以检测到 用户按了哪个键。下面的代码供您参考。希望对您有所帮助。

                  //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中没有文本,或者有一些文本,但光标在最开始。有趣的是,就我而言,我正是需要这种行为
                  • 在我的活动中没有 EditText,我只是让键盘以编程方式出现。我需要抓住每个软键盘键,这似乎是唯一可行的解​​决方案。另一种是覆盖 dispatchKeyEvent 方法。不幸的是,从 JellyBean 开始,IME 不会为 DELETE 键发送 KeyEvent。 developer.android.com/reference/android/view/KeyEvent.html
                  【解决方案18】:

                  你问已经有一段时间了,但我也遇到了同样的问题。正如 Estel 已经提到的,按键监听器的问题是它们只能使用硬件键盘。要使用 IME(软键盘),解决方案要复杂一些。

                  我们真正想要重写的单个方法是EditTextInputConnection 类中的sendKeyEvent。当 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>
                  

                  【讨论】:

                  • 我最近在 Jelly Bean 上遇到了同样的问题。我发现这个解决方案大部分都有效,除了我必须覆盖 deleteSurroundingText(...) 而不是 sendKeyEvent(...) (根本没有被调用)。希望这对其他人有帮助!
                  • 这个答案与上面的@Brandon 评论相结合,这对我有用。我现在想知道的是,这将如何在 JellyBean 之前的设备上工作。
                  • 它确实适用于我在 2.2 和 2.3 设备上接受的答案。
                  • 似乎在 2.3 上两次触发退格键事件...:/
                  • 当edittext为空时这不起作用,关于当edittext为空且没有文本时如何获取删除键事件的任何想法? 4.2
                  猜你喜欢
                  • 1970-01-01
                  • 2020-12-17
                  • 1970-01-01
                  • 1970-01-01
                  • 2011-02-24
                  • 2016-01-03
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多