如何检查Android中软件键盘的可见性?

我需要做一个非常简单的事情 – 找出是否显示软件键盘。 这是可能的Android?

    NEW ANSWER 于2012年1月25日添加

    自从编写下面的答案后,有人向我介绍ViewTreeObserver和朋友的存在, 这些 API自从版本1以来一直在SDK中潜伏。

    更简单的解决scheme是为活动的根视图提供一个已知的ID(比如@+id/activityRoot ,将GlobalLayoutListener挂钩到ViewTreeObserver中,然后计算活动的视图根和窗口大小:

     final View activityRootView = findViewById(R.id.activityRoot); activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() { @Override public void onGlobalLayout() { int heightDiff = activityRootView.getRootView().getHeight() - activityRootView.getHeight(); if (heightDiff > dpToPx(this, 200)) { // if more than 200 dp, it's probably a keyboard... // ... do something here } } }); 

    使用一个实用程序,如:

     public static float dpToPx(Context context, float valueInDp) { DisplayMetrics metrics = context.getResources().getDisplayMetrics(); return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, valueInDp, metrics); } 

    简单!

    注意:您的应用程序必须在Android Manifest android:windowSoftInputMode="adjustResize"设置此标志,否则上述解决scheme将无法工作。

    原来的答案

    是的,这是可能的,但是这远比它应该的更难。

    如果我需要关心键盘何时出现和消失(这是相当常见的),那么我所做的是将我的顶级布局类自定义为覆盖onMeasure() 。 基本的逻辑是,如果布局发现自己的填充显着小于窗口的总面积,那么软键盘可能正在显示。

     import android.app.Activity; import android.content.Context; import android.graphics.Rect; import android.util.AttributeSet; import android.widget.LinearLayout; /* * LinearLayoutThatDetectsSoftKeyboard - a variant of LinearLayout that can detect when * the soft keyboard is shown and hidden (something Android can't tell you, weirdly). */ public class LinearLayoutThatDetectsSoftKeyboard extends LinearLayout { public LinearLayoutThatDetectsSoftKeyboard(Context context, AttributeSet attrs) { super(context, attrs); } public interface Listener { public void onSoftKeyboardShown(boolean isShowing); } private Listener listener; public void setListener(Listener listener) { this.listener = listener; } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int height = MeasureSpec.getSize(heightMeasureSpec); Activity activity = (Activity)getContext(); Rect rect = new Rect(); activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(rect); int statusBarHeight = rect.top; int screenHeight = activity.getWindowManager().getDefaultDisplay().getHeight(); int diff = (screenHeight - statusBarHeight) - height; if (listener != null) { listener.onSoftKeyboardShown(diff>128); // assume all soft keyboards are at least 128 pixels high } super.onMeasure(widthMeasureSpec, heightMeasureSpec); } } 

    然后在你的Activity类中

     public class MyActivity extends Activity implements LinearLayoutThatDetectsSoftKeyboard.Listener { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ... LinearLayoutThatDetectsSoftKeyboard mainLayout = (LinearLayoutThatDetectsSoftKeyboard)findViewById(R.id.main); mainLayout.setListener(this); ... } @Override public void onSoftKeyboardShown(boolean isShowing) { // do whatever you need to do here } ... } 

    所以希望这可以帮助别人。

    Reuben Scratton给出的新答案非常好,而且效率很高,但是只有在将windowSoftInputMode设置为adjustResize时,它才会起作用。 如果将其设置为adjustPan,则仍然无法使用其代码片段检测键盘是否可见。 为了解决这个问题,我对上面的代码做了一个微小的修改。

     final View activityRootView = findViewById(R.id.activityRoot); activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() { @Override public void onGlobalLayout() { Rect r = new Rect(); //r will be populated with the coordinates of your view that area still visible. activityRootView.getWindowVisibleDisplayFrame(r); int heightDiff = activityRootView.getRootView().getHeight() - (r.bottom - r.top); if (heightDiff > 100) { // if more than 100 pixels, its probably a keyboard... ... do something here } } }); 

    对不起,对于迟到的答案,但我已经创build了一个小帮手类来处理打开/closures事件,通知监听器和其他有用的东西,可能有人会觉得有帮助:

     import android.graphics.Rect; import android.view.View; import android.view.ViewTreeObserver; import java.util.LinkedList; import java.util.List; public class SoftKeyboardStateWatcher implements ViewTreeObserver.OnGlobalLayoutListener { public interface SoftKeyboardStateListener { void onSoftKeyboardOpened(int keyboardHeightInPx); void onSoftKeyboardClosed(); } private final List<SoftKeyboardStateListener> listeners = new LinkedList<SoftKeyboardStateListener>(); private final View activityRootView; private int lastSoftKeyboardHeightInPx; private boolean isSoftKeyboardOpened; public SoftKeyboardStateWatcher(View activityRootView) { this(activityRootView, false); } public SoftKeyboardStateWatcher(View activityRootView, boolean isSoftKeyboardOpened) { this.activityRootView = activityRootView; this.isSoftKeyboardOpened = isSoftKeyboardOpened; activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(this); } @Override public void onGlobalLayout() { final Rect r = new Rect(); //r will be populated with the coordinates of your view that area still visible. activityRootView.getWindowVisibleDisplayFrame(r); final int heightDiff = activityRootView.getRootView().getHeight() - (r.bottom - r.top); if (!isSoftKeyboardOpened && heightDiff > 100) { // if more than 100 pixels, its probably a keyboard... isSoftKeyboardOpened = true; notifyOnSoftKeyboardOpened(heightDiff); } else if (isSoftKeyboardOpened && heightDiff < 100) { isSoftKeyboardOpened = false; notifyOnSoftKeyboardClosed(); } } public void setIsSoftKeyboardOpened(boolean isSoftKeyboardOpened) { this.isSoftKeyboardOpened = isSoftKeyboardOpened; } public boolean isSoftKeyboardOpened() { return isSoftKeyboardOpened; } /** * Default value is zero {@code 0}. * * @return last saved keyboard height in px */ public int getLastSoftKeyboardHeightInPx() { return lastSoftKeyboardHeightInPx; } public void addSoftKeyboardStateListener(SoftKeyboardStateListener listener) { listeners.add(listener); } public void removeSoftKeyboardStateListener(SoftKeyboardStateListener listener) { listeners.remove(listener); } private void notifyOnSoftKeyboardOpened(int keyboardHeightInPx) { this.lastSoftKeyboardHeightInPx = keyboardHeightInPx; for (SoftKeyboardStateListener listener : listeners) { if (listener != null) { listener.onSoftKeyboardOpened(keyboardHeightInPx); } } } private void notifyOnSoftKeyboardClosed() { for (SoftKeyboardStateListener listener : listeners) { if (listener != null) { listener.onSoftKeyboardClosed(); } } } } 

    用法示例:

     final SoftKeyboardStateWatcher softKeyboardStateWatcher = new SoftKeyboardStateWatcher(findViewById(R.id.activity_main_layout); // Add listener softKeyboardStateWatcher.addSoftKeyboardStateListener(...); // then just handle callbacks 

    就计算机而言,它一直是永恒的,但这个问题仍然是令人难以置信的相关!

    所以我已经采取了上述的答案,并结合和提炼了一下…

     public interface OnKeyboardVisibilityListener { void onVisibilityChanged(boolean visible); } public final void setKeyboardListener(final OnKeyboardVisibilityListener listener) { final View activityRootView = ((ViewGroup) getActivity().findViewById(android.R.id.content)).getChildAt(0); activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() { private boolean wasOpened; private final int DefaultKeyboardDP = 100; // From @nathanielwolf answer... Lollipop includes button bar in the root. Add height of button bar (48dp) to maxDiff private final int EstimatedKeyboardDP = DefaultKeyboardDP + (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP ? 48 : 0); private final Rect r = new Rect(); @Override public void onGlobalLayout() { // Convert the dp to pixels. int estimatedKeyboardHeight = (int) TypedValue .applyDimension(TypedValue.COMPLEX_UNIT_DIP, EstimatedKeyboardDP, activityRootView.getResources().getDisplayMetrics()); // Conclude whether the keyboard is shown or not. activityRootView.getWindowVisibleDisplayFrame(r); int heightDiff = activityRootView.getRootView().getHeight() - (r.bottom - r.top); boolean isShown = heightDiff >= estimatedKeyboardHeight; if (isShown == wasOpened) { Log.d("Keyboard state", "Ignoring global layout change..."); return; } wasOpened = isShown; listener.onVisibilityChanged(isShown); } }); } 

    适用于我:)

    注意:如果你注意到DefaultKeyboardDP不适合你的设备玩这个值,并发表一个评论给大家,知道应该是什么值…最终我们将得到正确的价值,以适应所有的设备!

    一些改进,以避免错误地检测高密度设备上的软键盘的可见性:

    1. 高度差的阈值应定义为128 dp ,而不是128像素
      请参阅Google关于度量和网格的devise文档 , 48 dp是触摸对象的舒适尺寸, 32 dp是button的最小尺寸。 通用软键盘应该包括4行按键,所以最小键盘高度应该是: 32 dp * 4 = 128 dp ,这意味着阈值大小应该通过乘以设备密度传输到像素。 对于xxxhdpi设备(密度4),软键盘高度阈值应为128 * 4 = 512像素。

    2. 根视图和其可见区域之间的高度差异:
      根视图高度 – 状态栏高度 – 可见框架高度=根视图底部 – 可见框架底部,因为状态栏高度等于根视图顶部的可见框架。

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

    我用了一点时间来解决这个问题……我运行了一些CastExceptions,但发现你可以使用类的名字replace你在layout.xml中的LinearLayout。

    喜欢这个:

     <?xml version="1.0" encoding="UTF-8"?> <LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent" xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/llMaster"> <com.ourshoppingnote.RelativeLayoutThatDetectsSoftKeyboard android:background="@drawable/metal_background" android:layout_width="fill_parent" android:layout_height="fill_parent" android:id="@+id/rlMaster" > <LinearLayout android:layout_width="fill_parent" android:layout_height="1dip" android:background="@drawable/line"></LinearLayout> .... </com.ourshoppingnote.RelativeLayoutThatDetectsSoftKeyboard> </LinearLayout> 

    这样你就不会遇到任何投射问题。

    …如果你不想在每个页面上这样做,我build议你使用“MasterPage in Android”。 在这里看到链接: http : //jnastase.alner.net/archive/2011/01/08/ldquomaster-pagesrdquo-in-android.aspx

    检查元素的高度是不可靠的,因为像WifiKeyboard一些键盘高度为零。

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

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

    这个想法是,如果您需要隐藏键盘并同时检查软input状态,请使用以下解决scheme:

     public boolean hideSoftInput() { InputMethodManager imm = (InputMethodManager) getSystemService(Activity.INPUT_METHOD_SERVICE); return imm.hideSoftInputFromWindow(mViewPager.getWindowToken(), 0); } 

    如果在隐藏之前显示键盘,则此方法返回true。

    而不是假设差异编码,我做了这样的事情,因为我在我的应用程序中有菜单选项。

     final View root= findViewById(R.id.myrootview); root.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() { @Override public void onGlobalLayout() { int heightDiff = root.getRootView().getHeight() - root.getHeight(); Rect rectgle= new Rect(); Window window= getWindow(); window.getDecorView().getWindowVisibleDisplayFrame(rectgle); int contentViewTop= window.findViewById(Window.ID_ANDROID_CONTENT).getTop(); if(heightDiff <= contentViewTop){ //Soft KeyBoard Hidden }else{ //Soft KeyBoard Shown } } }); 

    我发现,@ Reuben_Scratton的方法和@ Yogesh方法的组合似乎效果最好。 结合他们的方法会产生这样的事情:

     final View activityRootView = findViewById(R.id.activityRoot); activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() { @Override public void onGlobalLayout() { if (getResources().getConfiguration().keyboardHidden == Configuration.KEYBOARDHIDDEN_NO) { // Check if keyboard is not hidden // ... do something here } } }); 

    您可以使用活动的decorView观察软键盘的隐藏。

     public final class SoftKeyboardUtil { public static final String TAG = "SoftKeyboardUtil"; public static void observeSoftKeyBoard(Activity activity , final OnSoftKeyBoardHideListener listener){ final View decorView = activity.getWindow().getDecorView(); decorView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { Rect rect = new Rect(); decorView.getWindowVisibleDisplayFrame(rect); int displayHight = rect.bottom - rect.top; int hight = decorView.getHeight(); boolean hide = (double)displayHight / hight > 0.8 ; if(Log.isLoggable(TAG, Log.DEBUG)){ Log.d(TAG ,"DecorView display hight = "+displayHight); Log.d(TAG ,"DecorView hight = "+ hight); Log.d(TAG, "softkeyboard visible = " + !hide); } listener.onSoftKeyBoardVisible(!hide); } }); } public interface OnSoftKeyBoardHideListener{ void onSoftKeyBoardVisible(boolean visible); } } 

    这些解决scheme都不会用于棒棒糖。 在棒棒糖activityRootView.getRootView().getHeight()包含button栏的高度,而测量视图不包含。 我已经调整了上面最好的/最简单的解决scheme来处理棒棒糖。

      final View activityRootView = findViewById(R.id.activityRoot); activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() { @Override public void onGlobalLayout() { Rect r = new Rect(); //r will be populated with the coordinates of your view that area still visible. activityRootView.getWindowVisibleDisplayFrame(r); int heightDiff = activityRootView.getRootView().getHeight() - (r.bottom - r.top); Resources res = getResources(); // The status bar is 25dp, use 50dp for assurance float maxDiff = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 50, res.getDisplayMetrics()); //Lollipop includes button bar in the root. Add height of button bar (48dp) to maxDiff if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { float buttonBarHeight = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 48, res.getDisplayMetrics()); maxDiff += buttonBarHeight; } if (heightDiff > maxDiff) { // if more than 100 pixels, its probably a keyboard... ...do something here } } }); 

    我使用了Reuban答案的一个轻微变体,这在某些情况下被certificate是更有用的,尤其是在高分辨率的设备上。

     final View activityRootView = findViewById(android.R.id.content); 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 } } }); 

    就计算机而言,它一直是永恒的,但这个问题仍然令人难以置信地相关! 所以我已经采取了上述的答案,并结合和提炼了一下…

     public interface OnKeyboardVisibilityListener { void onVisibilityChanged(boolean visible); } public final void setKeyboardListener(final OnKeyboardVisibilityListener listener) { final View activityRootView = ((ViewGroup) getActivity().findViewById(android.R.id.content)).getChildAt(0); activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() { private boolean wasOpened; private final Rect r = new Rect(); @Override public void onGlobalLayout() { activityRootView.getWindowVisibleDisplayFrame(r); int heightDiff = activityRootView.getRootView().getHeight() - (r.bottom - r.top); boolean isOpen = heightDiff > 100; if (isOpen == wasOpened) { logDebug("Ignoring global layout change..."); return; } wasOpened = isOpen; listener.onVisibilityChanged(isOpen); } }); } 

    它适用于我。

    我的答案基本上和Kachi的答案一样,但是我把它包装到一个很好的帮助类中,以清理它在整个应用中的使用方式。

     import android.app.Activity; import android.app.Fragment; import android.graphics.Rect; import android.view.View; import android.view.ViewTreeObserver.OnGlobalLayoutListener; /** * Detects Keyboard Status changes and fires events only once for each change */ public class KeyboardStatusDetector { KeyboardVisibilityListener visibilityListener; boolean keyboardVisible = false; public void registerFragment(Fragment f) { registerView(f.getView()); } public void registerActivity(Activity a) { registerView(a.getWindow().getDecorView().findViewById(android.R.id.content)); } public KeyboardStatusDetector registerView(final View v) { v.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() { @Override public void onGlobalLayout() { Rect r = new Rect(); v.getWindowVisibleDisplayFrame(r); int heightDiff = v.getRootView().getHeight() - (r.bottom - r.top); if (heightDiff > 100) { // if more than 100 pixels, its probably a keyboard... /** Check this variable to debounce layout events */ if(!keyboardVisible) { keyboardVisible = true; if(visibilityListener != null) visibilityListener.onVisibilityChanged(true); } } else { if(keyboardVisible) { keyboardVisible = false; if(visibilityListener != null) visibilityListener.onVisibilityChanged(false); } } } }); return this; } public KeyboardStatusDetector setVisibilityListener(KeyboardVisibilityListener listener) { visibilityListener = listener; return this; } public static interface KeyboardVisibilityListener { public void onVisibilityChanged(boolean keyboardVisible); } } 

    你可以使用它来检测整个应用程序中任何位置的键盘变化

      new KeyboardStatusDetector() .registerFragment(fragment) //register to a fragment .registerActivity(activity) //or register to an activity .registerView(view) //or register to a view .setVisibilityListener(new KeyboardVisibilityListener() { @Override public void onVisibilityChanged(boolean keyboardVisible) { if(keyboardVisible) { //Do stuff for keyboard visible }else { //Do stuff for keyboard hidden } } }); 

    注意:只能使用“注册”呼叫之一。 他们都是一样的工作,只是为了方便

    你可以试试这个,对我很好:

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

    我刚刚遇到一个错误,同时使用上面的大多数解决scheme,build议添加一个固定的数字。

    S4是一个高分辨率,导致导航栏的高度是100px,因此我的应用程序认为键盘是开放的。

    所以所有新的高分辨率手机发布,我相信使用硬编码的价值是不是一个长期的好主意。

    在各种屏幕和设备上进行一些testing之后,我发现一个更好的方法是使用百分比。 获取decorView和你的应用程序内容之间的差异,然后检查差异的百分比。 从我得到的统计数据来看,大多数导航栏(不pipe大小,分辨率等)将占用屏幕的3%到5%。 在键盘打开的情况下,屏幕的占比在47%到55%之间。

    作为一个结论,我的解决scheme是检查差异是否超过10%,然后我假设它的键盘打开。

    在viewpager中改变片段的方向时,我很难保持键盘状态。 我不知道为什么,但它似乎是不吉利的,行为与标准活动不同。

    为了在这种情况下保持键盘状态,首先你应该把android:windowSoftInputMode = "stateUnchanged"到你的AndroidManifest.xml 。 但是,您可能会注意到,这实际上并不能解决整个问题 – 如果以前在方向更改之前打开了键盘,则键盘无法打开。 在所有其他情况下,这种行为似乎是正确的。

    那么,我们需要实现这里提到的解决scheme之一。 我find的最清洁的是George Maisuradze的 – 使用hideSoftInputFromWindow的布尔callback函数:

     InputMethodManager imm = (InputMethodManager) getSystemService(Activity.INPUT_METHOD_SERVICE); return imm.hideSoftInputFromWindow(mViewPager.getWindowToken(), 0); 

    我将这个值存储在我的Fragment的onSaveInstanceState方法,并检索它onCreate 。 然后,我在onCreateView强制显示键盘的值是否为true (如果键盘在碎片破坏之前实际隐藏之前是可见的,则返回true)。

    尝试这个:

     final View activityRootView = getWindow().getDecorView().getRootView(); activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { Rect r = new Rect(); //r will be populated with the coordinates of your view that area still visible. activityRootView.getWindowVisibleDisplayFrame(r); int heightDiff = activityRootView.getRootView().getHeight() - (r.bottom - r.top); if (heightDiff < activityRootView.getRootView().getHeight() / 4 ) { // if more than 100 pixels, its probably a keyboard... // ... do something here ... \\ } } }); 

    InputMethodManager有关于软键盘的信息。 您可以通过以下方式获得该活动:

     ((InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE)) 

    你可能会玩弄,看看它能告诉你什么。 您可以使用它来显示或隐藏软input…

    这是我的解决scheme,它的工作原理。 而不是寻找像素大小只是检查内容视图的高度已经改变或没有:

     // Scroll to the latest comment whenever the keyboard is shown commentsContent.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { private int oldHeight; @Override public void onGlobalLayout() { int newHeight = commentsContent.getMeasuredHeight(); if (newHeight < oldHeight) { // Check for the keyboard showing in case the height difference // is a result of orientation change if (isSoftKeyboardShowing(CommentsActivity.this)) { // Keyboard is showing so scroll to the latest comment scrollToLatestComment(); } } oldHeight = newHeight; } }); public static boolean isSoftKeyboardShowing(Activity activity) { InputMethodManager inputMethodManager = (InputMethodManager) activity.getSystemService(Activity.INPUT_METHOD_SERVICE); return inputMethodManager.isActive(); } 

    不要做任何硬编码。 最好的方法是你不得不调整你的意见,而获得关注EditText与KeyBord显示。 You can do this adding resize property on activity into Manifest file using below code.

    android:windowSoftInputMode="adjustResize"

    There is a direct method to find this out. And, it does not require any Layout changes.
    So, it works in immersive fullscreen mode, too.

    The trick is that you try to hide or show the soft keyboard and capture the result of that try.
    No panic, this does not really show or hide the keyboard. We just ask for the state.

    To stay up-to-date, you can simply repeat the operation, eg every 200 milliseconds, using a Handler.

    You find an implementation here: https://stackoverflow.com/a/27567074/2525452

    i think this method will help you to find out is keybord is visible or not.

      public Boolean isSoftKeyBoardVisible(){ InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE); if (imm.isAcceptingText()) { Log.d(TAG,"Software Keyboard was shown"); return true; } else { Log.d(TAG,"Software Keyboard was not shown"); return false; } } 

    Reuben Scratton's new answer (calculate the HeightDiff int heightDiff = activityRootView.getRootView().getHeight() - activityRootView.getHeight(); ) will not work in activity if you set the translucent status bar mode.

    if you use translucent status bar , activityRootView.getHeight() will never change weather the soft keyboard is visible. it will always return the height of activity and status bar.

    For example, Nexus 4, Android 5.0.1, set android:windowTranslucentStatus to true, it will return 1184 forever, even the ime have opend. If you set android:windowTranslucentStatus to false, it will return Height correctly, if ime invisible,it return 1134(not include the status bar)。close the ime, it will return 5xx maybe (depends on ime's height)

    I don't know weather this is a bug, I've try on 4.4.4 and 5.0.1, the result is same.

    So, up to now, the second most agreed answer, Kachi's solution will be the most safe way to calcute the height of ime. Here's a copy:

     final View activityRootView = findViewById(R.id.activityRoot); activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() { @Override public void onGlobalLayout() { Rect r = new Rect(); //r will be populated with the coordinates of your view that area still visible. activityRootView.getWindowVisibleDisplayFrame(r); int heightDiff = activityRootView.getRootView().getHeight() - (r.bottom - r.top); if (heightDiff > 100) { // if more than 100 pixels, its probably a keyboard... ... do something here } } }); 

    A method that doesn't need a LayoutListener

    In my case, I would like to save the state of the keyboard before replacing my Fragment. I call the method hideSoftInputFromWindow from onSaveInstanceState , which closes the keyboard and returns me whether the keyboard was visible or not.

    This method is straightforward but may change the state of your keyboard.

    I know that this is a old post but I think this is the simplest approach that I know and my test device is Nexus 5. I haven't tried it in other devices. Hope that others will share their approach if they find my code is not good 🙂

     public static boolean isKeyboardShown(Context context, View view) { if (context == null || view == null) { return false; } InputMethodManager imm = (InputMethodManager) context .getSystemService(Context.INPUT_METHOD_SERVICE); return imm.hideSoftInputFromWindow(view.getWindowToken(), 0); } 

    imm.hideSoftInputFromWindow returns boolean.

    谢谢,

     if (keyopen()) { InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); imm.toggleSoftInput(InputMethodManager.HIDE_IMPLICIT_ONLY,0); } 

    The above function is what I use to check if a Keyboard is visible. If it is, then I close it.

    Below shows the two methods required.

    First, define the workable Window height in onCreate.

     protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // add to onCreate method Rect rectgle= new Rect(); Window window= getWindow(); window.getDecorView().getWindowVisibleDisplayFrame(rectgle); sheight= rectgle.bottom; // } 

    Then, add a boolean method that gets the Window height at that instance. If it does not match the original (assuming you are not changing it along the way…) then, the keyboard is open.

     public boolean keyopen() { Rect rectgle= new Rect(); Window window= getWindow(); window.getDecorView().getWindowVisibleDisplayFrame(rectgle); int curheight= rectgle.bottom; if (curheight!=sheight) { return true; } else { return false; } } 

    Frotz!

    I know how exact you can determine if keyboard is hidden or not.

     public int getStatusBarHeight() { int result = 0; int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android"); if (resourceId > 0) { result = getResources().getDimensionPixelSize(resourceId); } return result; } public int getNavigationBarHeight() { int result = 0; int resourceId = getResources().getIdentifier("navigation_bar_height", "dimen", "android"); if (resourceId > 0) { result = getResources().getDimensionPixelSize(resourceId); } return result; } public boolean isKeyboardHidden() { int delta = mRootView.getRootView().getHeight() - mRootView.getHeight() - getNavigationBarHeight() - getStatusBarHeight() - getSupportActionBar().getHeight(); return delta <= 0; } 

    This works for tablets. When navigationbar is shown horizontally.

    Think has a easy way, like this:

     InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); imm.isActive(); 

    You can also see if him is active in a specific view:

     imm.isActive(View v);