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


当前回答

医生说… https://developer.android.com/reference/androidx/core/view/WindowInsetsCompat

检查放行说明.. https://developer.android.com/jetpack/androidx/releases/core#1.5.0-alpha02

要获得当前键盘可见性,可以使用getRootWindowInsets,然后调用isVisible()函数,传入IME类型。

val windowinsetscompat = ViewCompat.getRootWindowInsets(view)
val imeVisible = windowinsetscompat.isVisible(Type.ime())

也有监听OnApplyWindowInsetsListener的变化

ViewCompat.setOnApplyWindowInsetsListener(view) { v, insets ->
    val imeVisible = insets.isVisible(Type.ime())
}

其他回答

除了正确的答案,我必须在onCreateView的末尾添加这个,当使用一个片段内的webview。

getActivity().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);

可能是因为我在一个片段中运行Webview,或者可能是API 30上的一个新行为,我的问题是,即使显示键盘,片段的高度也从未改变。

所以对于Fragment,整个代码应该是

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View view = super.onCreateView(inflater, container, savedInstanceState);
    //mWebView.postUrl("https://www.google.com/");
    final View activityRootView = view;
    layoutListener = 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);
            // This variable was created only for Debug purposes and 
            // to see the height change when clicking on a field inside mWebView
            int screenHeight = activityRootView.getRootView().getHeight();
            Log.d("onGlobalLayout", "rect: " + r.toString());
            Log.d("onGlobalLayout", "screenHeight: " + screenHeight);

            //The difference on the heights from bottom to top and on the root height
            int heightDiff = screenHeight - (r.bottom - r.top);
            Log.d("onGlobalLayout", "heightDiff: " + heightDiff);

            //I suggest to put 250 on resources to have better order
            float dpx = dpToPx(getActivity(), 250);

            if (previousHeightDiff != heightDiff) {
                if (heightDiff > dpx) {
                    isSoftKeyboardPresent = true;
                } else {
                    isSoftKeyboardPresent = false;
                }
                previousHeightDiff = heightDiff;
            }
        }
    };
    activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(layoutListener);
    getActivity().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
    return view;
}

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

在使用上述大多数建议添加固定数字的解决方案时,我刚刚遇到了一个错误。

S4的dpi很高,导致导航栏的高度为100px,因此我的应用程序认为键盘一直是打开的。

所以,随着所有新的高分辨率手机的发布,我认为使用硬编码值从长远来看不是一个好主意。

在各种屏幕和设备上进行测试后,我发现一个更好的方法是使用百分比。 获取decorView和你的应用内容之间的差异,然后检查这个差异的百分比。 从我得到的统计数据来看,大多数导航栏(无论大小、分辨率等)将占据屏幕的3%到5%。如果键盘是打开的,它会占据屏幕的47%到55%。

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

这个解决方案可能会重新打开键盘,但它是有效的。

InputMethodManager inputManager = ( (InputMethodManager) this.getSystemService(Context.INPUT_METHOD_SERVICE) );

private boolean isKeyboardShowing() {

    boolean isKeyboardShowing = inputManager.hideSoftInputFromWindow(irrelevantView.getWindowToken(), 0);
    if (isKeyboardShowing) {
        inputManager.showSoftInput(this.getCurrentFocus(), 0);
    }
    return isKeyboardShowing;
}

你可以使用InputMethodManager。isActive方法,如果键盘可见则返回true:

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

你也可以看到键盘在一个特定的视图中是否处于活动状态:

    imm.isActive(View v);

你可以通过使用活动的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);
    }
}