我需要做一件非常简单的事情-找出软件键盘是否显示。这在Android中可行吗?


当前回答

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

Threshold of height difference should be defined as 128 dp, not 128 pixels. Refer to Google design doc about Metrics and Grid, 48 dp is comfortable size for touch object and 32 dp is minimum for buttons. Generic soft keyboard should include 4 rows of key buttons, so minimum keyboard height should be: 32 dp * 4 = 128 dp, that means threshold size should transfer to pixels by multiply device density. For xxxhdpi devices (density 4), the soft keyboard height threshold should be 128 * 4 = 512 pixels. Height difference between root view and its visible area: root view height - status bar height - visible frame height = root view bottom - visible frame bottom, since status bar height equal to the top of root view visible frame. 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; }

其他回答

我的答案基本上与Kachi的答案相同,但我将它包装到一个很好的helper类中,以清理它在整个应用程序中的使用方式。

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

注意:只使用一个“寄存器”调用。它们都是一样的,只是为了方便

Reuben Scratton的新答案(计算HeightDiff int HeightDiff = activityRootView.getRootView().getHeight() - activityRootView.getHeight();)如果您设置半透明状态栏模式,将无法在活动中工作。

如果你使用半透明状态栏,activityRootView.getHeight()将永远不会改变软键盘是否可见。它将始终返回活动和状态栏的高度。

例如,Nexus 4, Android 5.0.1,将Android:windowTranslucentStatus设置为true,它将永远返回1184,即使ime已经打开。如果你设置android:windowTranslucentStatus为false,它将正确返回高度,如果ime不可见,它将返回1134(不包括状态栏)。关闭ime,它可能会返回5xx(取决于ime的高度)

我不知道这是否是一个bug,我已经尝试了4.4.4和5.0.1,结果是一样的。

所以,到目前为止,第二个最被认可的答案,Kachi的解决方案将是最安全的方法来计算ime的高度。以下是一份复印件:

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

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

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

if (imm.isAcceptingText()) {
    //Software Keyboard was shown..
} else {
    //Software Keyboard was not shown..
}

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

在这种情况下,要保持键盘状态,首先你应该添加android:windowSoftInputMode = "stateUnchanged"到你的AndroidManifest.xml。不过,您可能会注意到,这实际上并没有解决整个问题——如果在方向改变之前打开了键盘,那么键盘就不会为我打开。在其他所有情况下,这种行为似乎都是正确的。

然后,我们需要实现这里提到的解决方案之一。 我发现的最干净的一个是George Maisuradze的——使用hideSoftInputFromWindow中的布尔回调:

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

我将这个值存储在我的Fragment的onSaveInstanceState方法中,并在onCreate中检索它。然后,我强制显示键盘在onCreateView,如果它有一个值为真(它返回真,如果键盘是可见的,实际上隐藏它之前的片段销毁)。

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

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

https://rogerkeays.com/how-to-check-if-the-software-keyboard-is-shown-in-android