如何检测Android设备上的软键盘是否可见?

331

在Android中,有没有一种方法可以检测软键盘是否显示在屏幕上?


2
可能是重复的问题:Android:如何判断软键盘是否显示? - Heath Hunnicutt
1
在某些情况下(如果安装了第三方键盘),解决方案可以是检查全局通知,因为当键盘打开时,会有一个系统通知显示“更改键盘”。这可以通过NotificationListenerService来完成。 - Prof
3
将近8年了,仍然没有可靠的解决方案。哦,如果他们介绍一个解决方案,它也只能适用于API > 30,所以没关系。 - M.kazem Akhgary
可能是Android:检测软键盘打开的重复问题。 - AbdelHady
如果你正在使用Espresso或Jetpack Compose进行UI测试,你可以使用executeShellCommand()来检测键盘是否显示在屏幕上:https://stackoverflow.com/questions/33970956/test-if-soft-keyboard-is-visible-using-espresso#53118977 - undefined
39个回答

0

有一种直接的方法可以找到这个问题的答案。而且,它不需要布局更改。
所以它也适用于沉浸式全屏模式。
但是,不幸的是,它并不适用于所有设备。因此,您必须使用您的设备进行测试。

诀窍在于尝试隐藏或显示软键盘,并捕获该尝试的结果。
如果它正确地工作,则键盘实际上并没有被显示或隐藏。我们只是询问状态。

为了保持最新,您只需重复此操作,例如每200毫秒使用处理程序。

下面的实现仅执行单个检查。
如果您进行多次检查,则应启用所有(_keyboardVisible)测试。

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

如何调用它以及在哪里调用? - Mahdi Astanei

0

这里有一个解决方案可以知道软键盘是否可见。

  1. 使用ActivityManager.getRunningServices(max_count_of_services)检查系统上运行的服务;
  2. 从返回的ActivityManager.RunningServiceInfo实例中,检查clientCount值以获取软键盘服务;
  3. 所述的clientCount将在每次显示软键盘时递增。例如,如果clientCount最初为1,则显示键盘时它将变为2;
  4. 在键盘解散时,clientCount将递减。在这种情况下,它将重置为1。

一些流行的键盘具有其classNames中的特定关键字:

  1. Google AOSP = IME
  2. Swype = IME
  3. Swiftkey = KeyboardService
  4. Fleksy = keyboard
  5. Adaptxt = IME (KPTAdaptxtIME)
  6. Smart = Keyboard (SmartKeyboard)

从ActivityManager.RunningServiceInfo中检查类名中的上述模式。 此外,ActivityManager.RunningServiceInfo的clientPackage = android,表示键盘已绑定到系统。

上面提到的信息可以结合起来以严格的方式找出软键盘是否可见。


0
如果您的应用程序支持 AndroidR 的 APIs,则可以使用以下方法。
In kotlin :
    var imeInsets = view.rootWindowInsets.getInsets(Type.ime()) 
    if (imeInsets.isVisible) { 
        view.translationX = imeInsets.bottom 
    }

注意:此功能仅适用于AndroidR及以下版本,其他版本需要遵循其他答案或我将为其更新。


0

这是我使用绑定实现的 Kotlin 方法:

在 Activity 的 onCreate 方法中,应该像这样添加 GlobalLayoutListener:

binding.root.apply {
            viewTreeObserver.addOnGlobalLayoutListener {
                Rect().let {
                    getWindowVisibleDisplayFrame(it)
                    val heightDiff = rootView.height - it.height()
                    isKeyboardVisible = heightDiff >= getKeyboardMarginOfError()                
                }
            }
        }

在上面的代码中,getKeyboardMarginOfError 是一个扩展函数,它的样子是这样的:
fun View.getKeyboardMarginOfError(): Int = convertDpToPx(50F).roundToInt()

fun View.convertDpToPx(dp: Float): Float {
    return TypedValue.applyDimension(
        TypedValue.COMPLEX_UNIT_DIP,
        dp,
        this.resources.displayMetrics
    )
}

值为50F的边距验证了键盘是否显示。


-1
我是这样做的,但只有在您的目标是关闭/打开键盘时才相关。
关闭示例:(检查键盘是否已关闭,如果没有-关闭)
imm.showSoftInput(etSearch, InputMethodManager.HIDE_IMPLICIT_ONLY, new ResultReceiver(null) {
                    @Override
                    protected void onReceiveResult(int resultCode, Bundle resultData) {
                        super.onReceiveResult(resultCode, resultData);
                        if (resultCode != InputMethodManager.RESULT_UNCHANGED_HIDDEN)
                            imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
                    }
                });

该问题与查找键盘是否显示有关。 - Gopal Singh Sirvi

-1

a 可能正在使用:

@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);

    Log.d(
    getClass().getSimpleName(), 
    String.format("conf: %s", newConfig));

    if (newConfig.hardKeyboardHidden != hardKeyboardHidden) {
        onHardwareKeyboardChange(newConfig.hardKeyboardHidden);

        hardKeyboardHidden = newConfig.hardKeyboardHidden;
    }

    if (newConfig.keyboardHidden != keyboardHidden) {
        onKeyboardChange(newConfig.keyboardHidden);

        keyboardHidden = newConfig.hardKeyboardHidden;
    }

}

public static final int KEYBOARDHIDDEN_UNDEFINED = 0;
public static final int KEYBOARDHIDDEN_NO = 1;
public static final int KEYBOARDHIDDEN_YES = 2;
public static final int KEYBOARDHIDDEN_SOFT = 3;

//todo
private void onKeyboardChange(int keyboardHidden) {

}

//todo
private void onHardwareKeyboardChange(int hardKeyboardHidden) {

}

1
这只适用于硬件键盘,而不是软件键盘。 - anthonymonori

-1

我写了示例

这个资源库可以帮助检测键盘状态,而不需要假设“键盘应该占屏幕的X以上的部分”。


-1

我曾经遇到过类似的问题。我需要对屏幕上的“Enter”按钮做出反应(隐藏键盘)。在这种情况下,您可以订阅打开键盘的文本视图的OnEditorAction事件 - 如果您有多个可编辑框,则订阅所有可编辑框。

在您的Activity中,您完全控制键盘,因此如果您监听所有打开和关闭事件,则在任何时候都不会面临键盘是否打开的问题。


对我来说不起作用。我只收到OnEditorAction中的Enter键。 - 3c71

-2

你可以试试这个,对我来说很好用

InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
    if (imm.isActive())
        //Keyboard is active

这里是有关编程的内容,请将其翻译成中文。请只返回已翻译的文本:与软件虚拟键盘无关。 - user924

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接