Show/Hide Fragment 中的软键盘事件

Show/Hide Soft Keyboard event in Fragment

有很多关于查找 show/hide 软键盘事件的帖子。 我发现自己处于需要根据软键状态在片段中更改图标的情况。

我试图实现 onMeasure,但我无法在我的片段中覆盖它。 是否有一种(相对)无痛的方式在我的片段中获得干净的 show/hide 软键盘事件,或者我应该放弃发货?

遗憾但真实 - android 软件键盘上没有本机显示事件。

处理键盘被隐藏这一事实的一种方法是检查输入的符号和后退按钮按下(例如 textEdit 甚至会收到后退按钮)——但它的解决方案不够灵活。

另一种可能的解决方案是: 覆盖 activity 中的 onMeasure,然后通知观察者(模式观察者)——例如片段。 Fragment 应该自己订阅和取消订阅 onPause onResume 事件。类似于 activity 代码:

private class DialogActivityLayout extends LinearLayout {

        public DialogActivityLayout(Context context, AttributeSet attributeSet) {
            super(context, attributeSet);
            LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            inflater.inflate(R.layout.activity_dialog, this);
        }

        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            final int proposedHeight = MeasureSpec.getSize(heightMeasureSpec);
            final int actualHeight = getHeight();

            /* Layout loaded */
            if (actualHeight == 0 || proposedHeight == actualHeight) {
                super.onMeasure(widthMeasureSpec, heightMeasureSpec);
                return;
            }

            if (proposedHeight > actualHeight) {
                DialogActivity.this.onKeyboardHide();
            } else {
                DialogActivity.this.onKeyboardShow();
            }
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        }
    }

我不确定,但我记得它仅适用于 LinearLayout,当然 activity 应该设置 adjustResize 标志(以编程方式或在清单中)

另一个(我认为更好的方法)是像这里一样使用 globalTree observer

SoftKeyboard open and close listener in an activity in Android?

经过一番努力,我能够抽象出一个方法,只要我需要显示或隐藏键盘,我就可以调用该方法,而无需使用我在许多答案中看到的 SHOW_FORCED 结果是键盘打开即使在没有文本输入的新 activity 上。

我在 onGlobalLayout 中使用了这个 code 来检查键盘是否打开,然后在我的方法中我决定是打开还是关闭。

代码如下:

检查是否打开:

private static boolean isKeyboardVisible(Activity activity) {
    Rect r = new Rect();
    View contentView = activity.findViewById(android.R.id.content);
    contentView.getWindowVisibleDisplayFrame(r);
    int screenHeight = contentView.getRootView().getHeight();
    int keypadHeight = screenHeight - r.bottom;

    return (keypadHeight > screenHeight * 0.15);
}

执行我需要的操作(这里是我调用上述方法的地方):

public static void toggleKeyboard(final Activity activity, final boolean showKeyboard) {
    final InputMethodManager imm =
            (InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE);

    // The Handler is needed because the method that checks if the keyboard
    // is open need some time to get the updated value from the activity,
    // e.g. when my activity return to foreground. 
    new Handler().postDelayed(new Runnable() {
        public void run() {
            // This 'if' just check if my app still in foreground 
            // when the code is executed to avoid any problem.
            // I've leave out of the answer to keep short, you may use your own.
            if(Tools.isAppInForeground(activity)) {
                // Check the keyboard.
                boolean isVisible = isKeyboardVisible(activity);

                // If I want to show the keyboard and it's not visible, show it!
                if (showKeyboard && !isVisible) {
                    imm.toggleSoftInput(InputMethodManager.SHOW_IMPLICIT,
                            InputMethodManager.HIDE_IMPLICIT_ONLY);

                // If I want to hide and the keyboard is visible, hide it!
                } else if (!showKeyboard && isVisible) {
                    imm.toggleSoftInput(InputMethodManager.HIDE_IMPLICIT_ONLY, 0);
                }
            }
        }
    }, 100);

}

要使用,我就这样调用:

toggleKeyboard(myactivity, true); // show
// or
toggleKeyboard(myactivity, false); // hide