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

在Android中有没有办法检测软件(又名“软”)键盘在屏幕上是否可见?

没有直接的方法 – 请参阅http://groups.google.com/group/android-platform/browse_thread/thread/1728f26f2334c060/5e4910f0d9eb898a其中来自Android团队的Dianne Hackborn已回复。 但是,您可以通过检查#onMeasure中的窗口大小是否更改来间接检测到它。 请参阅如何检查Android中软件键盘的可见性? 。

这对我有用。 也许这是所有版本的最佳方式。

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 } else { // keyboard is closed } } }); 

尝试这个:

 InputMethodManager imm = (InputMethodManager) getActivity() .getSystemService(Context.INPUT_METHOD_SERVICE); if (imm.isAcceptingText()) { writeToLog("Software Keyboard was shown"); } else { writeToLog("Software Keyboard was not shown"); } 

我创build了一个简单的类,可以用于这个: https : //github.com/ravindu1024/android-keyboardlistener 。 只需将其复制到您的项目并使用,如下所示:

 KeyboardUtils.addKeyboardToggleListener(this, new KeyboardUtils.SoftKeyboardToggleListener() { @Override public void onToggleSoftKeyboard(boolean isVisible) { Log.d("keyboard", "keyboard visible: "+isVisible); } }); 

好简单

1.把id放在你的根视图上

在这种情况下, rootView只是一个指向我的根视图的视图。

 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/addresses_confirm_root_view" android:background="@color/WHITE_CLR"> 

2.在你的活动中初始化你的根视图:

RelativeLayout rootView = (RelativeLayout) findViewById(R.id.addresses_confirm_root_view); 3.使用getViewTreeObserver()检测键盘是否打开或closures

  rootView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { int heightDiff = rootView.getRootView().getHeight() - rootView.getHeight(); if (heightDiff > 100) { Log.e("MyActivity", "keyboard opened"); } else { Log.e("MyActivity", "keyboard closed"); } } }); 

你可以参考这个答案 – https://stackoverflow.com/a/24105062/3629912

它每次都为我工作。

 adb shell dumpsys window InputMethod | grep "mHasSurface" 

如果软件键盘可见,它将返回true。

您可以使用showSoftInput()和hideSoftInput()的callback结果来检查键盘的状态。 全部细节和示例代码在

http://www.ninthavenue.com.au/how-to-check-if-the-software-keyboard-is-shown-in-android

我用这个作为基础: http : //www.ninthavenue.com.au/how-to-check-if-the-software-keyboard-is-shown-in-android

 /** * To capture the result of IMM hide/show soft keyboard */ public class IMMResult extends ResultReceiver { public int result = -1; public IMMResult() { super(null); } @Override public void onReceiveResult(int r, Bundle data) { result = r; } // poll result value for up to 500 milliseconds public int getResult() { try { int sleep = 0; while (result == -1 && sleep < 500) { Thread.sleep(100); sleep += 100; } } catch (InterruptedException e) { Log.e("IMMResult", e.getMessage()); } return result; } } 

然后写下这个方法:

 public boolean isSoftKeyboardShown(InputMethodManager imm, View v) { IMMResult result = new IMMResult(); int res; imm.showSoftInput(v, 0, result); // if keyboard doesn't change, handle the keypress res = result.getResult(); if (res == InputMethodManager.RESULT_UNCHANGED_SHOWN || res == InputMethodManager.RESULT_UNCHANGED_HIDDEN) { return true; } else return false; } 

然后,您可以使用它来testing可能已经打开软键盘的所有字段(EditText,AutoCompleteTextView等):

  InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE); if(isSoftKeyboardShown(imm, editText1) | isSoftKeyboardShown(imm, autocompletetextview1)) //close the softkeyboard imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0); 

毫无疑问,这不是一个理想的解决scheme,但它完成了工作。

试试这个代码它真的工作,如果KeyboardShown是显示那么这个函数返回真值….

 private final String TAG = "TextEditor"; private TextView mTextEditor; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_editor); mTextEditor = (TextView) findViewById(R.id.text_editor); mTextEditor.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { isKeyboardShown(mTextEditor.getRootView()); } }); } private boolean isKeyboardShown(View rootView) { /* 128dp = 32dp * 4, minimum button height 32dp and generic 4 rows soft keyboard */ final int SOFT_KEYBOARD_HEIGHT_DP_THRESHOLD = 128; Rect r = new Rect(); rootView.getWindowVisibleDisplayFrame(r); DisplayMetrics dm = rootView.getResources().getDisplayMetrics(); /* heightDiff = rootView height - status bar height (r.top) - visible frame height (r.bottom - r.top) */ int heightDiff = rootView.getBottom() - r.bottom; /* Threshold size: dp to pixels, multiply with display density */ boolean isKeyboardShown = heightDiff > SOFT_KEYBOARD_HEIGHT_DP_THRESHOLD * dm.density; Log.d(TAG, "isKeyboardShown ? " + isKeyboardShown + ", heightDiff:" + heightDiff + ", density:" + dm.density + "root view height:" + rootView.getHeight() + ", rect:" + r); return isKeyboardShown; } 

在我的情况下,我只有一个EditText来pipe理我的布局,所以我想出了这个解决scheme。 它工作的很好,基本上它是一个自定义的EditText ,用于监听焦点并在焦点改变或者按下后退/结束button时发送本地广播。 为了工作,需要在android:focusable="true"android:focusableInTouchMode="true" clearFocus() android:focusableInTouchMode="true"的布局中放置一个虚拟View ,因为当您调用clearFocus() ,焦点将被重新分配到第一个可聚焦视图。 虚拟视图示例:

 <View android:layout_width="1dp" android:layout_height="1dp" android:focusable="true" android:focusableInTouchMode="true"/> 

其他信息

检测布局变化差异的解决scheme不能很好地工作,因为它很大程度上取决于屏幕密度,因为在某个设备中100px可能很多,而其他一些设备可能会有误报。 另外不同的供应商有不同的键盘。

这对我所需要的要求来说要简单得多。 希望这可能有所帮助:

在主要活动:

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

mKeyboardStatus的默认主要布尔值将被初始化为false

然后检查值如下,并在必要时执行一个操作:

  mSearchBox.requestFocus(); if(!isKeyboardActive()){ showKeyboard(); }else{ dismissKeyboard(); } 

我有一个类似的问题。 我需要对屏幕上的inputbutton作出反应(隐藏键盘)。 在这种情况下,您可以订阅文本视图的OnEditorAction,键盘被打开 – 如果您有多个可编辑框,则订阅所有这些框。

在您的活动中,您可以完全控制键盘,因此,如果您聆听所有开启和closures事件,则无论您是否打开键盘,都不会面临问题。

我通过设置GlobalLayoutListener来做到这一点,如下所示:

 final View activityRootView = findViewById(R.id.activityRoot); activityRootView.getViewTreeObserver().addOnGlobalLayoutListener( new OnGlobalLayoutListener() { @Override public void onGlobalLayout() { int heightView = activityRootView.getHeight(); int widthView = activityRootView.getWidth(); if (1.0 * widthView / heightView > 3) { //Make changes for Keyboard not visible } else { //Make changes for keyboard visible } } }); 

有一个直接的方法来find这个。 而且,它不需要布局更改。
因此,它也可以在身临其境的全屏模式下工作。
但不幸的是,它不适用于所有设备。 所以你必须用你的设备来testing它。

诀窍是你试图隐藏或显示软键盘,并捕获该尝试的结果。
如果它工作正确,那么键盘是不是真的显示或隐藏。 我们只是要求国家。

要保持最新状态,只需使用Handler重复此操作,例如每200毫秒。

下面的实现只是一个检查。
如果你做了多个检查,那么你应该启用所有的(_keyboardVisible)testing。

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

在Android中,您可以通过ADB shell进行检测。 我写和使用这个方法:

 { JSch jsch = new JSch(); try { Session session = jsch.getSession("<userName>", "<IP>", 22); session.setPassword("<Password>"); Properties config = new Properties(); config.put("StrictHostKeyChecking", "no"); session.setConfig(config); session.connect(); ChannelExec channel = (ChannelExec)session.openChannel("exec"); BufferedReader in = new BufferedReader(new InputStreamReader(channel.getInputStream())); channel.setCommand("C:/Android/android-sdk/platform-tools/adb shell dumpsys window InputMethod | findstr \"mHasSurface\""); channel.connect(); String msg = null; String msg2 = " mHasSurface=true"; while ((msg = in.readLine()) != null) { Boolean isContain = msg.contains(msg2); log.info(isContain); if (isContain){ log.info("Hiding keyboard..."); driver.hideKeyboard(); } else { log.info("No need to hide keyboard."); } } channel.disconnect(); session.disconnect(); } catch (JSchException | IOException | InterruptedException e) { e.printStackTrace(); } } } 

这是一个解决方法,知道软键盘是否可见。

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

一些stream行的键盘在他们的class级中有一定的关键字:

  1. Google AOSP = IME
  2. Swype = IME
  3. Swiftkey = KeyboardService
  4. Fleksy =键盘
  5. Adaptxt = IME(KPTAdaptxtIME)
  6. 智能键盘(SmartKeyboard)

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

上面提到的信息可以组合在一起,以便严格地了解软键盘是否可见。

@iWantScala的答案是伟大的,但不为我工作
rootView.getRootView().getHeight()始终具有相同的值

一种方法是定义两个variables

 private int maxRootViewHeight = 0; private int currentRootViewHeight = 0; 

添加全局侦听器

 rootView.getViewTreeObserver() .addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { currentRootViewHeight = rootView.getHeight(); if (currentRootViewHeight > maxRootViewHeight) { maxRootViewHeight = currentRootViewHeight; } } }); 

然后检查

 if (currentRootViewHeight >= maxRootViewHeight) { // Keyboard is hidden } else { // Keyboard is shown } 

工作正常

我做了如下,但它只有当你的目标是closures/打开键盘它relevet。

closures示例:(检查键盘是否已经closures,如果没有closures)

 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); } }); 
 final View activityRootView = findViewById(R.id.rootlayout); activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { Rect r = new Rect(); activityRootView.getWindowVisibleDisplayFrame(r); int screenHeight = activityRootView.getRootView().getHeight(); Log.e("screenHeight", String.valueOf(screenHeight)); int heightDiff = screenHeight - (r.bottom - r.top); Log.e("heightDiff", String.valueOf(heightDiff)); boolean visible = heightDiff > screenHeight / 3; Log.e("visible", String.valueOf(visible)); if (visible) { Toast.makeText(LabRegister.this, "I am here 1", Toast.LENGTH_SHORT).show(); } else { Toast.makeText(LabRegister.this, "I am here 2", Toast.LENGTH_SHORT).show(); } } }); 

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

我最好的经验是做我自己的键盘