How do I detect if software keyboard is visible on Android Device or not?

前端 未结 30 1389
情书的邮戳
情书的邮戳 2020-11-22 10:59

Is there a way in Android to detect if the software (a.k.a. \"soft\") keyboard is visible on screen?

相关标签:
30条回答
  • 2020-11-22 11:28

    There is a direct method to find this out. And, it does not require the layout changes.
    So it works in immersive fullscreen mode, too.
    But, unfortunately, it does not work on all devices. So you have to test it with your device(s).

    The trick is that you try to hide or show the soft keyboard and capture the result of that try.
    If it works correct then the keyboard is not really shown or hidden. We just ask for the state.

    To stay up-to-date, you simply repeat this operation, e.g. every 200 milliseconds, using a Handler.

    The implementation below does just a single check.
    If you do multiple checks, then you should enable all the (_keyboardVisible) tests.

    public interface OnKeyboardShowHide
    {
        void    onShowKeyboard( Object param );
        void    onHideKeyboard( Object param );
    }
    
    private static Handler      _keyboardHandler    = new Handler();
    private boolean             _keyboardVisible    = false;
    private OnKeyboardShowHide  _keyboardCallback;
    private Object              _keyboardCallbackParam;
    
    public void start( OnKeyboardShowHide callback, Object callbackParam )
    {
        _keyboardCallback      = callback;
        _keyboardCallbackParam = callbackParam;
        //
        View view = getCurrentFocus();
        if (view != null)
        {
            InputMethodManager imm = (InputMethodManager) getSystemService( Activity.INPUT_METHOD_SERVICE );
            imm.hideSoftInputFromWindow( view.getWindowToken(), InputMethodManager.HIDE_IMPLICIT_ONLY, _keyboardResultReceiver );
            imm.showSoftInput( view, InputMethodManager.SHOW_IMPLICIT, _keyboardResultReceiver );
        }
        else // if (_keyboardVisible)
        {
            _keyboardVisible = false;
            _keyboardCallback.onHideKeyboard( _keyboardCallbackParam );
        }
    }
    
    private ResultReceiver      _keyboardResultReceiver = new ResultReceiver( _keyboardHandler )
    {
        @Override
        protected void onReceiveResult( int resultCode, Bundle resultData )
        {
            switch (resultCode)
            {
                case InputMethodManager.RESULT_SHOWN :
                case InputMethodManager.RESULT_UNCHANGED_SHOWN :
                    // if (!_keyboardVisible)
                    {
                        _keyboardVisible = true;
                        _keyboardCallback.onShowKeyboard( _keyboardCallbackParam );
                    }
                    break;
                case InputMethodManager.RESULT_HIDDEN :
                case InputMethodManager.RESULT_UNCHANGED_HIDDEN :
                    // if (_keyboardVisible)
                    {
                        _keyboardVisible = false;
                        _keyboardCallback.onHideKeyboard( _keyboardCallbackParam );
                    }
                    break;
            }
        }
    };
    
    0 讨论(0)
  • 2020-11-22 11:30

    This works for me. Maybe this is always the best way for all versions.

    It would be effective to make a property of keyboard visibility and observe this changes delayed because the onGlobalLayout method calls many times. Also it is good to check the device rotation and windowSoftInputMode is not adjustNothing.

    boolean isKeyboardShowing = false;
    void onKeyboardVisibilityChanged(boolean opened) {
        print("keyboard " + opened);
    }
    
    // ContentView is the root view of the layout of this activity/fragment    
    contentView.getViewTreeObserver().addOnGlobalLayoutListener(
        new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
    
            Rect r = new Rect();
            contentView.getWindowVisibleDisplayFrame(r);
            int screenHeight = contentView.getRootView().getHeight();
    
            // r.bottom is the position above soft keypad or device button.
            // if keypad is shown, the r.bottom is smaller than that before.
            int keypadHeight = screenHeight - r.bottom;
    
            Log.d(TAG, "keypadHeight = " + keypadHeight);
    
            if (keypadHeight > screenHeight * 0.15) { // 0.15 ratio is perhaps enough to determine keypad height.
                // keyboard is opened
                if (!isKeyboardShowing) {
                    isKeyboardShowing = true
                    onKeyboardVisibilityChanged(true)
                }
            }
            else {
                // keyboard is closed
                if (isKeyboardShowing) {
                    isKeyboardShowing = false
                    onKeyboardVisibilityChanged(false)
                }
            }
        }
    });
    
    0 讨论(0)
  • 2020-11-22 11:31

    try this:

    InputMethodManager imm = (InputMethodManager) getActivity()
                .getSystemService(Context.INPUT_METHOD_SERVICE);
    
        if (imm.isAcceptingText()) {
            writeToLog("Software Keyboard was shown");
        } else {
            writeToLog("Software Keyboard was not shown");
        }
    
    0 讨论(0)
  • 2020-11-22 11:31

    This was much less complicated for the requirements I needed. Hope this might help:

    On the MainActivity:

    public void dismissKeyboard(){
        InputMethodManager imm =(InputMethodManager)this.getSystemService(Context.INPUT_METHOD_SERVICE);
        imm.hideSoftInputFromWindow(mSearchBox.getWindowToken(), 0);
        mKeyboardStatus = false;
    }
    
    public void showKeyboard(){
        InputMethodManager imm =(InputMethodManager)this.getSystemService(Context.INPUT_METHOD_SERVICE);
        imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, InputMethodManager.HIDE_IMPLICIT_ONLY);
        mKeyboardStatus = true;
    }
    
    private boolean isKeyboardActive(){
        return mKeyboardStatus;
    }
    

    The default primative boolean value for mKeyboardStatus will be initialized to false.

    Then check the value as follows, and perform an action if necessary:

     mSearchBox.requestFocus();
        if(!isKeyboardActive()){
            showKeyboard();
        }else{
            dismissKeyboard();
        }
    
    0 讨论(0)
  • 2020-11-22 11:31

    I wrote sample.

    This repository can help to detect keyboard status without assumption that "keyboard should be more than X part of screen"

    0 讨论(0)
  • 2020-11-22 11:32

    With the new feature WindowInsetsCompat in androidx core release 1.5.0-alpha02 you could check the visibility of the soft keyboard easily as below

    Quoting from reddit comment

    val View.keyboardIsVisible: Boolean
        get() = WindowInsetsCompat
            .toWindowInsetsCompat(rootWindowInsets)
            .isVisible(WindowInsetsCompat.Type.ime())
    

    Some note about backward compatibility, quoting from release notes

    New Features

    The WindowInsetsCompat APIs have been updated to those in the platform in Android 11. This includes the new ime() inset type, which allows checking the visibility and size of the on-screen keyboard.

    Some caveats about the ime() type, it works very reliably on API 23+ when your Activity is using the adjustResize window soft input mode. If you’re instead using the adjustPan mode, it should work reliably back to API 14.

    References

    • Twitter WindowInsetsCompat announcement
    • Reddit thread
    • Androidx Core 1.5.0-alpha02 release notes
    • WindowInsetsCompat Docs
    0 讨论(0)
提交回复
热议问题