译文:https://pspdfkit.com/blog/2016/keyboard-handling-on-android/
在Android中使用Keyboard有时非常纠结。曾经有个项目在pdf文件上添加注释,我们为这个问题纠结过很多次。下面时我们的处理方式。
监听软键盘的显示和隐藏
默认情况下,显示软键盘的时候,只是软键盘覆盖在我们的UI上。一般情况下没有什么问题,但是像下面这种情况重要的内容会倍软键盘覆盖掉:
一般情况下可以使用内置的方式使程序的布局重写测量,以防止内容被覆盖掉。在manifest的activity标签上用android:windowSoftInputMode=”adjustResize” ,如果你希望在代码中或者动态修改可以这样:
activity.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
在这里我们使用自定义控件来显示pdf文档,获取控件的正确大小很简单:重写onSizeChanged(int, int, int, int)方法,只需要正确实现这个方法,这个控件就可以在keyboard显示和隐藏的时候显示正确。
全屏模式
使用 adjustResize可以正常工作。但是,并不适用于全屏模式。官方文档对SOFT_INPUT_ADJUST_RESIZE这样描述的:
If the window's layout parameter flags include FLAG_FULLSCREEN, this value for softInputMode will be ignored; the window will not resize, but will stay fullscreen.
通过研究发现,全屏模式下布局高度不会重新测量。尽管如此,全屏模式下view中的fitSystemWindows(Rect)可以监测到软键盘的显示和隐藏。
需要监听变化的view调用setFitsSystemWindows(true),改变这个属性后,view将默认消耗(system bar,actionbar, navigation bar)以及软件盘的变化。如果你不想消耗掉这个window尺寸,可以在自定义view中重写这个方法,修改它的默认行为。
小贴士:fitSystemWindows这个方法在5.0以上废弃了,可以使用onApplyWindowInsets()函数,如果需要子view来处理,可以调用dispatchApplyWindowInsets()。
监听软键盘的显示
我们需要软键盘显示的时候可以滚动来编辑pdf的注释,但是不幸的时android中没有api可以监听软件盘时否显示。
一般的解决方式时使用adjustResize和监听contenView的OnGlobalLayoutListener,可以通过监听view的大小有没有变化超过某一个特定的值 来判断软键盘是否有显示,但通过上面的分析我们知道在全屏的时候view没有resize,所以这时候时不行的。全屏的时候我们可以通过fitSystemWindow来知道软键盘有否显示,所以至少我们可以定义个自定义控件来判断软件盘在这个时候有否显示。
通过对源码的学习,我们找到来一个更好的方案。
getWindowVisibleDisplayFrame(Rect)
通过这个方法可以知道view的可见范围。
通过观察decorview的可见范围的变化,我们不管是否在全屏模式下都可以轻易的知道软键盘是否有显示:
//软键盘最小高度
final int MIN_KEYBOARD_HEIGHT_PX = 150;
//decor view
final View decorView = activity.getWindow().getDecorView();
decorView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
private final Rect windowVisibleDisplayFrame = new Rect();
private int lastVisibleDecorViewHeight;
@Override
public void onGlobalLayout() {
//获取decorview的可见范围
decorView.getWindowVisibleDisplayFrame(windowVisibleDisplayFrame);
final int visibleDecorViewHeight = windowVisibleDisplayFrame.height();
// 通过decorview高度变化判断是否显示来软键盘
if (lastVisibleDecorViewHeight != 0) {
if (lastVisibleDecorViewHeight > visibleDecorViewHeight + MIN_KEYBOARD_HEIGHT_PX) {
// 计算当前软键盘高度(这个高度包含来全屏时navigation bar的高度).
int currentKeyboardHeight = decorView.getHeight() - windowVisibleDisplayFrame.bottom;
listener.onKeyboardShown(currentKeyboardHeight);
} else if (lastVisibleDecorViewHeight + MIN_KEYBOARD_HEIGHT_PX < visibleDecorViewHeight) {
listener.onKeyboardHidden();
}
}
//保存decorview高度
lastVisibleDecorViewHeight = visibleDecorViewHeight;
}
});
这里除了知道软键盘是否有显示,同时也获取到的软键盘的确切高度。最终。通过软键盘的高度作为全屏模式下我们的自定义控件和底部的距离。使用这种方式既不需要重写view的onSizeChanged()方法,也不需要在我们的自定义控件上对fitSystemWindows作处理。
最终效果如图: