[ING] Android软键盘之殇

Posted by 阿呆 on 2018-12-28

前言

先回顾几个概念

Window、ViewRootImpl、DocorView、Activity
Rect | ScrollTo

Rect(left,top,right,bittom),可以表示一个即将绘制的区域,也常用来作为参数来获取控件的轮廓
ScrollTo(x,y)

getWindowVisibleDisplayFrame(rect) / View.java

得到当前View attachTo的window的可见区域,它的基准坐标系是Window内的坐标系,关于这个函数,正常情况下,它是不包括底部导航栏的(back/home),后面我们会说到这点为什么很关键

如何处理软键盘与用户的交互

设置 Androidmanifest.xml 中 Activity的softInputMode属性

通过AjustPan或者AjustResize把任务交给系统处理,这样就会缺乏定制,经常当我们需要一些特殊需求的时候,还是得自己来实现,一般需要监听到软键盘的状态和高度

软键盘状态监听

通过监听软键盘的弹出或者隐藏,来自己实现相关的逻辑,可定制化强
其实这个监听有很多坑,如果遇到觉得不正常的地方,最好打印一下相关坐标的log,好具体问题具体分析,特别是主题是否是全屏

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
//window就是整个屏幕,状态栏、底部操作栏会导致它部分不可见,这点很关键
//root这里我们传的Activity的布局(不包括标题栏),因为我们不想移动标题栏,viewToScroll传入的是我们想要不被遮盖的View,也就是说,我们不一定要将root布局移动整个软键盘的高度
private void controlKeyboardLayout(final View root, final View viewToScroll) {
root.getViewTreeObserver().addOnGlobalLayoutListener( new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
Rect rect = new Rect();

root.getRootView().getWindowVisibleDisplayFrame(rect);
Log.d(TAG, "onGlobalLayout: visible rect: "+rect);
//获取root在窗体的不可视区域高度(被其他View遮挡的区域高度)
int rootInvisibleHeight = root.getRootView().getHeight() - rect.bottom;
//如果软键盘没有弹出,这里得到的就是底部操作栏的高度 //
//若不可视区域高度大于100,则键盘显示,后面显示,100不行,因为底部操作栏168,所以设成200
Log.d(TAG, "onGlobalLayout: invisible height "+rootInvisibleHeight);
if (rootInvisibleHeight > 200) { //键盘弹出 ,这个值很重要,一定要把底部操作栏的高度考虑进去!!
// 底部操作栏也算在了不可见的区域内,之前100一直出错,因为底部操作栏168,很难受!怪不得每次进来就会进入弹出键盘的流程
//而且,要搞清楚什么是不可见!状态按和底部操作栏应该都不属于这个window的范畴,而且弹出来的软键盘也不是
int[] location = new int[2];
//获取viewToScroll在窗体的坐标
viewToScroll.getLocationInWindow(location);
//计算root滚动高度,使viewToScroll在可见区域
int scrollHeight = (location[1] + viewToScroll.getHeight()) - rect.bottom;
Log.d(TAG, "onGlobalLayout: scrollheight "+scrollHeight);
//不能这样写,scrollTo是滑动内容,它只会对该View可见,也就是说,它的内容滑出了该View就不可见了,
// 所以,你如果直接使用要华东的View。scrollTo,你会发现
//滑动完了之后看不到任何东西
//viewToScroll.scrollTo(0,scrollHeight);

root.scrollTo(0,scrollHeight);
} else {
//键盘隐藏
root.scrollTo(0,0);
}
}
});
}