如何检测软件键盘在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(); } } }
这是一个解决方法,知道软键盘是否可见。
- 使用ActivityManager.getRunningServices(max_count_of_services)检查系统上运行的服务;
- 从返回的ActivityManager.RunningServiceInfo实例中,检查软键盘服务的clientCount值。
- 前面提到的clientCount会每次递增,显示软键盘。 例如,如果clientCount最初为1,则显示键盘时为2。
- 在解除键盘上,clientCount递减。 在这种情况下,它重置为1。
一些stream行的键盘在他们的class级中有一定的关键字:
- Google AOSP = IME
- Swype = IME
- Swiftkey = KeyboardService
- Fleksy =键盘
- Adaptxt = IME(KPTAdaptxtIME)
- 智能键盘(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) { }
我最好的经验是做我自己的键盘