引发的问题

键盘弹出后和界面互相作用一般有如下问题:

  • 键盘遮挡你想看到的内容
  • 键盘压缩你的界面变形
  • 键盘自动弹出
  • 键盘把界面顶出窗口

暂时想到这几种情况,由于最近做一个聊天的软件,遇到一些问题,所以想把类似问题全搞清楚,解决方法做如下总结。

1. 先看看各种情况下,键盘对界面干了啥都。

Android 软键盘弹出recyclerview上划 安卓键盘弹出_android

Android 软键盘弹出recyclerview上划 安卓键盘弹出_控件_02

默认情况
默认情况,输入法只管顶起你点击的输入框,保证这个输入框能方便的输入,这是它的核心任务,其他的不管,如上第一个图。

那么这时候它到底做了什么操作呢,我们可以多放点控件上去观察:

Android 软键盘弹出recyclerview上划 安卓键盘弹出_输入法_03

Android 软键盘弹出recyclerview上划 安卓键盘弹出_android_04

通过上面两幅图比较,我们从背景的情况来看,界面没有被压缩,而且把最上面的控件搞没了,说明是把整个界面顶上去了。

然后再看两幅图:

Android 软键盘弹出recyclerview上划 安卓键盘弹出_android_05

Android 软键盘弹出recyclerview上划 安卓键盘弹出_压缩_06

这两幅图的界面是添加了scrollview的,那么其他情况不变的情况下,效果发生了变化,为了使编辑框刚好输入,背景图被压缩了,但是最上边没有放入scrollview的控件却没有被顶上去。

这两次对比,可以得出结论:默认情况下没有scrollview、listview等控件的界面上,弹出键盘会直接将整个界面原封不动的往上顶,直到可以方便输入;而有scrollview等滚动控件的界面,弹出键盘会压缩这部分可滚动控件,直到可以方便输入。当然并不是只压缩这个滚动控件,而是和它重叠的部分界面都跟着压缩,因为那个背景图片并不是scrollview的背景,而是父控件的

以上是默认情况,我们知道activity标签中可以配置一个android:windowSoftInputMode参数,对压缩界面有影响的是这几个值:

adjustResize
adjustPan
adjustNothing
adjustUnspecified

除了这几个值还有其他值,这里不做介绍。

接着用这种方法测试这几个值,发现如下结论:

  • adjustResize:
    有滚动控件,会压缩滚动控件来保证输入框刚好输入;而没有滚动控件,不保证正好能输入,其实就是只管自己顶上来,盖住谁算谁。而且无论界面有没有可滚动控件,都将压缩父布局控件。键盘会自动弹出。
  • adjustPan:
    如果输入框高于键盘弹出的高度,那不会对界面造成任何影响,也不会压缩背景图等。如果输入框低于键盘弹出高度,不管有没有滚动控件,不会压缩任何界面,会把整个界面往上顶。键盘不自动弹出。
  • adjustNothing:
    不做任何事,不管有没有滚动控件,能不能正确输入,什么都不会做。键盘不自动弹出。
  • adjustUnspecified:
    这个其实就是不填值的默认值,现象上面已经详细说过,通过对比可以发现,其实就是根据有没有滚动控件,自动选择了adjustPan和adjustResize这两种情况。这个值其实最大保证了能使输入框刚好方便输入。但是最大程度保证了这一点,也就意味着,最大程度的不会顾及其他控件的情况。

2 遇到显示不理想的情况如何处理

通过上面我们知道了各种情况下键盘对界面的影响情况。那么如果遇到问题,如何解决呢。

1 键盘自动弹出的情况,上面已经分析,通过调整android:windowSoftInputMode,可以容易的解决。

2 控件压缩的情况,设置adjustPan,不会压缩任何界面

3 控件被顶出界面外,肯定是设置了adjustPan,改为别的就行了

其实2和3已经冲突,想要不压缩,又不整个往上顶,输入框高的话还好,低的话,那肯定就遮挡了。所以我们重点解决遮挡问题。

  • 适当选择android:windowSoftInputMode值:如果输入框较高,又不希望压缩界面及控件,适合adjustPan;如果希望方便输入,还能不遮挡其他控件,那可以选择adjustResize,然后通过适当的把一些控件放到滚动控件中,并在键盘弹出后,适当滚动控件到合适位置。或者当键盘弹出后,向上平移某个控件,键盘落下后,再移动回来。

这里提供几个函数,因为解决遮挡问题,需要两个关键因素:监听键盘弹出,测量键盘高度

监听键盘弹出:

private boolean isKeyboardShown(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;
}

view.getRootView().getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            if(isKeyboardShown(recyclerView.getRootView())){
                recyclerView.scrollToPosition(recyclerView.getAdapter().getItemCount()-1);
            }
        }
    });

这就是在rootview上加一个布局变化的监听,监听到布局变化,就判断是否键盘弹出,判断标准是,rootview的底部和窗口底部的距离差,这个距离差就是键盘的高度。我们可以设置大于多少就算是键盘弹出了。

获取键盘高度:

private int getKeyboardHight(View rootView){
    Rect r = new Rect();
    rootView.getWindowVisibleDisplayFrame(r);
    DisplayMetrics dm = rootView.getResources().getDisplayMetrics();
    int heightDiff = rootView.getBottom() - r.bottom;
    return heightDiff;
}

有了这些基础,可以适当的滑动滚动控件,适当的平移控件了。