我想根据是否显示虚拟键盘来改变布局。我已经搜索了API和各种博客,但似乎找不到任何有用的东西。

这可能吗?

谢谢!


当前回答

你也可以检查第一个DecorView的子底部填充。当键盘显示时,它将被设置为非零值。

@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
    View view = getRootView();
    if (view != null && (view = ((ViewGroup) view).getChildAt(0)) != null) {
        setKeyboardVisible(view.getPaddingBottom() > 0);
    }
    super.onLayout(changed, left, top, right, bottom);
}

其他回答

2020年更新

这现在是可能的:

在Android 11上,你可以这样做

view.setWindowInsetsAnimationCallback(object : WindowInsetsAnimation.Callback {
    override fun onEnd(animation: WindowInsetsAnimation) {
        super.onEnd(animation)
        val showingKeyboard = view.rootWindowInsets.isVisible(WindowInsets.Type.ime())
        // now use the boolean for something
    }
})

你也可以听显示/隐藏键盘的动画,并做相应的转换。

我建议阅读Android 11预览版和相应的文档

Android 11之前

但是,这项工作还没有Compat版本,所以您需要求助于黑客。

你可以得到窗口的insets,如果底部的insets大于一些值,你认为是合理的(通过实验),你可以认为这是显示键盘。这不是很好,在某些情况下可能会失败,但没有框架支持这一点。

这是对这个确切问题的一个很好的回答https://stackoverflow.com/a/36259261/372076。或者,这里有一个页面给出了一些不同的方法来实现这个在Android 11之前:

https://developer.salesforce.com/docs/atlas.en-us.noversion.service_sdk_android.meta/service_sdk_android/android_detecting_keyboard.htm


Note

此解决方案不适用于软键盘和 onConfigurationChanged将不会被soft (virtual)调用 键盘。


您必须自己处理配置更改。

http://developer.android.com/guide/topics/resources/runtime-changes.html#HandlingTheChange

示例:

// from the link above
@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);

    
    // Checks whether a hardware keyboard is available
    if (newConfig.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_NO) {
        Toast.makeText(this, "keyboard visible", Toast.LENGTH_SHORT).show();
    } else if (newConfig.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_YES) {
        Toast.makeText(this, "keyboard hidden", Toast.LENGTH_SHORT).show();
    }
}

然后只需更改一些视图的可见性,更新字段,并更改布局文件。

就像@amalBit的答案一样,注册一个全局布局的监听器,并计算dectorView的可见底部和建议底部的差值,如果差值大于某个值(猜测IME的高度),我们认为IME是up的:

    final EditText edit = (EditText) findViewById(R.id.edittext);
    edit.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            if (keyboardShown(edit.getRootView())) {
                Log.d("keyboard", "keyboard UP");
            } else {
                Log.d("keyboard", "keyboard Down");
            }
        }
    });

private boolean keyboardShown(View rootView) {

    final int softKeyboardHeight = 100;
    Rect r = new Rect();
    rootView.getWindowVisibleDisplayFrame(r);
    DisplayMetrics dm = rootView.getResources().getDisplayMetrics();
    int heightDiff = rootView.getBottom() - r.bottom;
    return heightDiff > softKeyboardHeight * dm.density;
}

高度阈值100是IME猜测的最小高度。

这适用于adjustPan和adjuststresize。

不确定是否有人发布这篇文章。发现这个解决方案简单易用!SoftKeyboard类在gi.github.com上。但是当键盘弹出/隐藏事件回调时,我们需要一个处理程序来正确地在UI上做事情:

/*
Somewhere else in your code
*/
RelativeLayout mainLayout = findViewById(R.layout.main_layout); // You must use your root layout
InputMethodManager im = (InputMethodManager) getSystemService(Service.INPUT_METHOD_SERVICE);

/*
Instantiate and pass a callback
*/
SoftKeyboard softKeyboard;
softKeyboard = new SoftKeyboard(mainLayout, im);
softKeyboard.setSoftKeyboardCallback(new SoftKeyboard.SoftKeyboardChanged()
{

    @Override
    public void onSoftKeyboardHide() 
    {
        // Code here
        new Handler(Looper.getMainLooper()).post(new Runnable() {
                @Override
                public void run() {
                    // Code here will run in UI thread
                    ...
                }
            });
    }

    @Override
    public void onSoftKeyboardShow() 
    {
        // Code here
        new Handler(Looper.getMainLooper()).post(new Runnable() {
                @Override
                public void run() {
                    // Code here will run in UI thread
                    ...
                }
            });

    }   
});

隐藏|显示事件键盘可以通过简单的hack在OnGlobalLayoutListener监听:

 final View activityRootView = findViewById(R.id.top_root);
        activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
            public void onGlobalLayout() {
                int heightDiff = activityRootView.getRootView().getHeight() - activityRootView.getHeight();

                if (heightDiff > 100) {
                    // keyboard is up
                } else {
                    // keyboard is down
                }
            }
        });

这里activityRootView是Activity的根视图。

你也可以检查第一个DecorView的子底部填充。当键盘显示时,它将被设置为非零值。

@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
    View view = getRootView();
    if (view != null && (view = ((ViewGroup) view).getChildAt(0)) != null) {
        setKeyboardVisible(view.getPaddingBottom() > 0);
    }
    super.onLayout(changed, left, top, right, bottom);
}