zoukankan      html  css  js  c++  java
  • Android 获取软键盘的删除delete事件

    对于软键盘删除事件,网上有很多方案是如下,但是 google api也说明了,这个只是监听硬件键盘,对于软键盘并不负责触发(我测试了一下,软键盘能够监听delete键,其他键像数字字母等没有触发这里的监听方法)。

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

    当然,也有是通过TextWatcher来处理delete事件,但是这个监听只在数据变化时才触发,如果edittext本身就没有内容,此时点击软件盘delete键也就不会触发这里的方法。

    类似于下面的逻辑:

    @Override
    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
        mPreviousLength = s.length();
    }
    
    @Override
    public void onTextChanged(CharSequence s, int start, int before, int count) {
    }
    
    @Override
    public void afterTextChanged(Editable s) {
        mBackSpace = mPreviousLength > s.length();
    
        if (mBackSpace) {
    
            // do your stuff ...
    
        } 
    }

    其实对于软件盘的监听,还要从源头找起,这里先介绍一下自定义view输入

    Android之自定义View来接收输入法输入的内容

    对于很多新人来讲,能接收输入法输入的内容大概只有EditText和TextView这两个控件了,其实不然,只要是View的子类,都可以接收输入法输入的内容。

    现在我们一步一步来实现,第一步我们得有一个View的子类。

    [html] view plain copy print?
    1. //首先我们得重写View中的一个方法,返回true,就是让这个View变成文本可编辑的状态,默认返回false。   
    2. @Override public boolean onCheckIsTextEditor() {   
    3.     return true;   
    4.     }   
    5.     //第二个就是重写方法,需要返回一个InputConnect对象,这个是和输入法输入内容的桥梁。  
    6. public InputConnection onCreateInputConnection(EditorInfo outAttrs);  
    7.   
    8. // outAttrs就是我们需要设置的输入法的各种类型最重要的就是:  
    9. outAttrs.imeOptions = EditorInfo.IME_FLAG_NO_EXTRACT_UI; outAttrs.inputType = InputType.TYPE_NULL;  
    //首先我们得重写View中的一个方法,返回true,就是让这个View变成文本可编辑的状态,默认返回false。 
    @Override public boolean onCheckIsTextEditor() { 
        return true; 
        } 
        //第二个就是重写方法,需要返回一个InputConnect对象,这个是和输入法输入内容的桥梁。
    public InputConnection onCreateInputConnection(EditorInfo outAttrs);
    
    // outAttrs就是我们需要设置的输入法的各种类型最重要的就是:
    outAttrs.imeOptions = EditorInfo.IME_FLAG_NO_EXTRACT_UI; outAttrs.inputType = InputType.TYPE_NULL;
    


    这里我只是随便设置,重要的是返回的InputConnect对象。以下是

    [html] view plain copy print?
    1. InputConnection   
    InputConnection 

    需要重写的方法

    [java] view plain copy print?
    1. //一般我们都是些一个BaseInputConnection的子类,而BaseInputConnection是实现了InputConnection接口的。  
    2.   
    3. 需要注意的就是几个方法注意重写。  
    4.   
    5. @Override  
    6. public boolean commitText(CharSequence text, int newCursorPosition) {   
    7.      Log.d("hickey", "commitText:" + text + " " + newCursorPosition);  
    8.      if (containsEmoji(text.toString())) {   
    9.         Log.d("hickey", "send emoji");   
    10.         return true;  
    11.      }   
    12.      if (mPlayer != null && mPlayFragment.isInputMethodStatus()) {  
    13.           Log.d("hickey", "text:" + text);   
    14.           mPlayerView.sendCharEvent(text.toString());  
    15.      }   
    16.     return true;  
    17.  }  
    18.   
    19. note:这个是当输入法输入了字符,包括表情,字母、文字、数字和符号。我们可以通过text筛选出我们不想让显示到自定义view上面。  
    20.   
    21. //有文本输入,当然也有按键输入,也别注意的是有些输入法输入数字并非用commitText方法传递,而是用按键来代替,比如KeyCode_1是代表1等。  
    22.   
    23.     @Override  
    24.     public boolean sendKeyEvent(KeyEvent event) {  
    25.         /** 当手指离开的按键的时候 */  
    26.         if (event.getAction() == KeyEvent.ACTION_DOWN) {  
    27.             Log.d("hickey", "sendKeyEvent:KeyCode=" + event.getKeyCode());  
    28.             if (event.getKeyCode() == KeyEvent.KEYCODE_DEL) {  
    29.                 mPlayerView.sendFunctionKeyCodeEvent(KeyEvent.KEYCODE_DEL);  
    30.             } else if (event.getKeyCode() == KeyEvent.KEYCODE_ENTER) {  
    31.                 mPlayerView.sendFunctionKeyCodeEvent(KeyEvent.KEYCODE_ENTER);  
    32.                 mPlayFragment.setInputMethodStatus(false, 1);  
    33.             } else {  
    34.                 mPlayerView.sendCharKeyCodeEvent(event.getKeyCode());  
    35.             }  
    36.         }  
    37.         return true;  
    38.     }  
    39.   
    40. note:这里我只做了删除,回车按键的处理,由于会触发动作按下和松开两次,所以在这里只做了按下的处理。  
    41.   
    42. //当然删除的时候也会触发  
    43. @Override  
    44.     public boolean deleteSurroundingText(int beforeLength, int afterLength) {  
    45.         Log.d("hickey", "deleteSurroundingText " + "beforeLength=" + beforeLength + " afterLength=" + afterLength);  
    46.         mPlayerView.sendFunctionKeyCodeEvent(KeyEvent.KEYCODE_DEL);  
    47.         return true;  
    48.     }  
    49.   
    50.  @Override  
    51.     public boolean finishComposingText() {  
    52.         //结束组合文本输入的时候  
    53.         Log.d("hickey", "finishComposingText");  
    54.         return true;  
    55.     }  
    56. //这个方法基本上会出现在切换输入法类型,点击回车(完成、搜索、发送、下一步)点击输入法右上角隐藏按钮会触发。  
    57.   
    58. 这里引申出多个问题,比如说当我们点击View上的时候,需要弹出输入法咋办?  
    59. 我们可以通过InputMethodManager来控制输入法弹起和缩回。  
    60.   
    61.     InputMethodHelper(Context mContext) {  
    62.         inputMethodManager = (InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE);  
    63.     }  
    64.   
    65.     public synchronized static InputMethodHelper getInstance(Context mContext) {  
    66.         synchronized (InputMethodHelper.class) {  
    67.             if (inputMethodHelper == null) {  
    68.                 inputMethodHelper = new InputMethodHelper(mContext);  
    69.             }  
    70.             return inputMethodHelper;  
    71.         }  
    72.     }  
    73.     /** 
    74.      * 显示软键盘 
    75.      * 
    76.      * @param view 
    77.      */  
    78.     public void showSoftInput(View view) {  
    79.         inputMethodManager.showSoftInput(view, 0);  
    80.     }  
    81.   
    82.     /** 
    83.      * 隐藏输入法 
    84.      */  
    85.     public void hideSoftInput(View view) {  
    86.         if (inputMethodManager.isActive()) {  
    87.             Log.d("hickey", "hideSoftInput:" + "hideSoftInputFromWindow");  
    88.             inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), 0);  
    89.         }  
    90.     }  
    91.   
    92. 在非全屏状态下,我们可以通过布局大小的改变来监听输入法的弹起和缩回,但是在全屏状态下呢,抱歉,目前是不可以的。比如说用户点击了输入法的隐藏按钮,只会触发finishComposingText这个方法,但是其他时候也会触发此方法,所以想通过此方法监听输入法缩回是不可行的,InputMethodManager也没有提供相关的API,试过获取IMM的提供的  
    93.   
    94.     public boolean isActive(View view){  
    95.         return inputMethodManager.isActive(view);  
    96.     }  
    97.   
    98.     public boolean isActive(){  
    99.         return inputMethodManager.isActive();  
    100.     }  
    101.   
    102.     public boolean isWatchingCursor (View view){  
    103.         return inputMethodManager.isWatchingCursor(view);  
    104.     }  
    105.   
    106.     public boolean isAcceptingText(){  
    107.         return inputMethodManager.isAcceptingText();  
    108.     }  
    109.   
    110.    
    //一般我们都是些一个BaseInputConnection的子类,而BaseInputConnection是实现了InputConnection接口的。
    
    需要注意的就是几个方法注意重写。
    
    @Override
    public boolean commitText(CharSequence text, int newCursorPosition) { 
         Log.d("hickey", "commitText:" + text + "	" + newCursorPosition);
         if (containsEmoji(text.toString())) { 
            Log.d("hickey", "send emoji"); 
            return true;
         } 
         if (mPlayer != null && mPlayFragment.isInputMethodStatus()) {
              Log.d("hickey", "text:" + text); 
              mPlayerView.sendCharEvent(text.toString());
         } 
        return true;
     }
    
    note:这个是当输入法输入了字符,包括表情,字母、文字、数字和符号。我们可以通过text筛选出我们不想让显示到自定义view上面。
    
    //有文本输入,当然也有按键输入,也别注意的是有些输入法输入数字并非用commitText方法传递,而是用按键来代替,比如KeyCode_1是代表1等。
    
        @Override
        public boolean sendKeyEvent(KeyEvent event) {
            /** 当手指离开的按键的时候 */
            if (event.getAction() == KeyEvent.ACTION_DOWN) {
                Log.d("hickey", "sendKeyEvent:KeyCode=" + event.getKeyCode());
                if (event.getKeyCode() == KeyEvent.KEYCODE_DEL) {
                    mPlayerView.sendFunctionKeyCodeEvent(KeyEvent.KEYCODE_DEL);
                } else if (event.getKeyCode() == KeyEvent.KEYCODE_ENTER) {
                    mPlayerView.sendFunctionKeyCodeEvent(KeyEvent.KEYCODE_ENTER);
                    mPlayFragment.setInputMethodStatus(false, 1);
                } else {
                    mPlayerView.sendCharKeyCodeEvent(event.getKeyCode());
                }
            }
            return true;
        }
    
    note:这里我只做了删除,回车按键的处理,由于会触发动作按下和松开两次,所以在这里只做了按下的处理。板面
    
    //当然删除的时候也会触发
    @Override
        public boolean deleteSurroundingText(int beforeLength, int afterLength) {
            Log.d("hickey", "deleteSurroundingText " + "beforeLength=" + beforeLength + " afterLength=" + afterLength);
            mPlayerView.sendFunctionKeyCodeEvent(KeyEvent.KEYCODE_DEL);
            return true;
        }
    
     @Override
        public boolean finishComposingText() {
            //结束组合文本输入的时候
            Log.d("hickey", "finishComposingText");
            return true;
        }
    //这个方法基本上会出现在切换输入法类型,点击回车(完成、搜索、发送、下一步)点击输入法右上角隐藏按钮会触发。
    
    这里引申出多个问题,比如说当我们点击View上的时候,需要弹出输入法咋办?
    我们可以通过InputMethodManager来控制输入法弹起和缩回。
    
        InputMethodHelper(Context mContext) {
            inputMethodManager = (InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE);
        }
    
        public synchronized static InputMethodHelper getInstance(Context mContext) {
            synchronized (InputMethodHelper.class) {
                if (inputMethodHelper == null) {
                    inputMethodHelper = new InputMethodHelper(mContext);
                }
                return inputMethodHelper;
            }
        }
        /**
         * 显示软键盘
         *
         * @param view
         */
        public void showSoftInput(View view) {
            inputMethodManager.showSoftInput(view, 0);
        }
    
        /**
         * 隐藏输入法
         */
        public void hideSoftInput(View view) {
            if (inputMethodManager.isActive()) {
                Log.d("hickey", "hideSoftInput:" + "hideSoftInputFromWindow");
                inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), 0);
            }
        }
    
    在非全屏状态下,我们可以通过布局大小的改变来监听输入法的弹起和缩回,但是在全屏状态下呢,抱歉,目前是不可以的。比如说用户点击了输入法的隐藏按钮,只会触发finishComposingText这个方法,但是其他时候也会触发此方法,所以想通过此方法监听输入法缩回是不可行的,InputMethodManager也没有提供相关的API,试过获取IMM的提供的
    
        public boolean isActive(View view){
            return inputMethodManager.isActive(view);
        }
    
        public boolean isActive(){
            return inputMethodManager.isActive();
        }
    
        public boolean isWatchingCursor (View view){
            return inputMethodManager.isWatchingCursor(view);
        }
    
        public boolean isAcceptingText(){
            return inputMethodManager.isAcceptingText();
        }
    
     


    都没有任何成效。

    还有一种情况是当前Activity退出了,输入法还健在,且输入了没有任何内容。而且我们试过所有隐藏输入法的方法,都无法正常的隐藏输入法。

    这里告诉告诉大家一个比较贱的方法,在输入法健在的时候,我们点击返回按钮,都会主动隐藏输入法,再次点击才会把按键事件分发传递到Activity上。

    所以,我们就需要模拟一个返回的事件。

    [java] view plain copy print?
    1. new Thread(new Runnable() {  
    2.                 @Override  
    3.                 public void run() {  
    4.                     RedFinger.simulationEvent = true;  
    5.                     Instrumentation instrumentation = new Instrumentation();  
    6.                     instrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_BACK);  
    7.                 }  
    8.             }).start();  
    new Thread(new Runnable() {
                    @Override
                    public void run() {
                        RedFinger.simulationEvent = true;
                        Instrumentation instrumentation = new Instrumentation();
                        instrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_BACK);
                    }
                }).start();



    //这里弄了个bool标志是防止输入已经隐藏还会分发返回按键事件到Activity上,所以需要在可能退出到的页面上

    看了这里后,你就可以了解怎么获取软键盘的事件了。

    在stackoverflow上也有很多讨论,我找到了两篇文章

    https://stackoverflow.com/questions/4886858/android-edittext-deletebackspace-key-event

    https://stackoverflow.com/questions/18581636/android-cannot-capture-backspace-delete-press-in-soft-keyboard/34857618#34857618

    这里面找到了一个不错的解决方案,重写edittext,代码如下

    [java] view plain copy print?
    1. public class WiseEditText extends AppCompatEditText {    
    2.     
    3.     
    4.     private OnKeyListener keyListener;    
    5.     
    6.     public WiseEditText(Context context, AttributeSet attrs, int defStyle) {    
    7.         super(context, attrs, defStyle);    
    8.     }    
    9.     
    10.     public WiseEditText(Context context, AttributeSet attrs) {    
    11.         super(context, attrs);    
    12.     }    
    13.     
    14.     public WiseEditText(Context context) {    
    15.         super(context);    
    16.     }    
    17.     
    18.     @Override    
    19.     public InputConnection onCreateInputConnection(EditorInfo outAttrs) {    
    20.         return new MyInputConnection(super.onCreateInputConnection(outAttrs),    
    21.                 true);    
    22.     }    
    23.     
    24.     private class MyInputConnection extends InputConnectionWrapper {    
    25.     
    26.         public MyInputConnection(InputConnection target, boolean mutable) {    
    27.             super(target, mutable);    
    28.         }    
    29.     
    30.         @Override    
    31.         public boolean sendKeyEvent(KeyEvent event) {    
    32.             if (keyListener != null) {    
    33.                 keyListener.onKey(WiseEditText.this,event.getKeyCode(),event);    
    34.             }    
    35.             return super.sendKeyEvent(event);    
    36.         }    
    37.     
    38.         @Override    
    39.         public boolean deleteSurroundingText(int beforeLength, int afterLength) {           
    40.             // magic: in latest Android, deleteSurroundingText(1, 0) will be called for backspace    
    41.             if (beforeLength == 1 && afterLength == 0) {    
    42.                 // backspace    
    43.                 return sendKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL))    
    44.                     && sendKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DEL));    
    45.             }    
    46.     
    47.             return super.deleteSurroundingText(beforeLength, afterLength);    
    48.         }    
    49.     
    50.     }    
    51.     
    52.    //设置监听回调    
    53.     public void setSoftKeyListener(OnKeyListener listener){    
    54.         keyListener = listener;    
    55.     }    
    56.     
    57. }  
    public class WiseEditText extends AppCompatEditText {  
      
      
        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;  
        }  
      
    }



    [java] view plain copy print?
      1. <pre snippet_file_name="blog_20170805_5_3934361" code_snippet_id="2519238"></pre>  
      2. <pre></pre>  
      3. <pre></pre>  
      4.      
  • 相关阅读:
    第十章 Ingress
    第九章 Service
    第八章 资源控制器
    第一章 Xshell5评估期已过问题
    第七章 yaml格式
    第六章 资源清单
    第五章 配置私有仓库Harbor
    第四章 K8s部署安装
    36 SpringBoot 在系统配置文件中动态加载配置
    Java 集合、数组 任意个数数字相加等于一个指定的数
  • 原文地址:https://www.cnblogs.com/beef/p/7296347.html
Copyright © 2011-2022 走看看