软键盘遮挡的解决

软键盘遮挡有两类,一类是完全遮挡,一类是遮挡一部分。
为什么会出现遮挡?
软键盘是一个dialog,有InputMethodService创建。当我们点击输入框时,系统会对当前的主窗口进行调整,以便留出相应的空间来显示该Dialog在底部。我们快速过一下源码便得知:
InputMethodService继承AbstractInputMethodService,继承Service。 只挑重点过一下,InputMethodService的oncreate方法里,可以看到创建SoftInputWindow地方,并且是bottom,还可以看到很多别的信息,比如横向parent,纵向自适应。

一、完全遮挡的解决

这个比较好解决,可以通过给Activity设置windowSoftInputMode这个属性来控制软键盘与Activity的主窗口的交互方式,Activity 的主窗口与包含屏幕软键盘的窗口的交互方式,该属性的设置影响两个方面:
1)当Activity成为用户注意的焦点时软键盘的状态 (隐藏还是可见)。
2)对Activity主窗口所做的调整
(意思是是否将其尺寸调小为软键盘腾出空间,或者当窗口部分被软键盘遮挡时是否平移其内容以使当前焦点可见)
该设置是下面所列的值之一,或者是一个“state…”值加上一个“adjust…”值的组合,state…控制软键盘显示还是隐藏,adjust…是否对软键盘进行调整。
从网上摘出这些字段的含义:
(1)控制软键盘显示还是隐藏
stateUnspecified-不指定软键盘的状态(隐藏还是可见) 将由系统选择合适的状态,或依赖主题中的设置,这是对软键盘行为的默认设置
stateUnchanged-保留状态 当 Activity 转至前台时保留软键盘最后所处的任何状态,无论是可见还是隐藏
stateHidden-隐藏软键盘 当用户确实是向前导航到 Activity,而不是因离开另一Activity 而返回时隐藏软键盘
stateAlwaysHidden-始终隐藏软键盘 当 Activity 的主窗口有输入焦点时始终隐藏软键盘
stateVisible-显示软键盘 在正常的适宜情况下(当用户向前导航到 Activity 的主窗口时)显示软键盘
stateAlwaysVisible-显示软键盘 当用户确实是向前导航到 Activity,而不是因离开另一Activity 而返回时.
(2)在软键盘弹出时,是否需要Activity对此进行调整
adjustUnspecified 主窗口的默认行为,不指定 Activity 的主窗口是否调整尺寸以为软键盘腾出空间,或者窗口内容是否进行平移以在屏幕上显露当前焦点。 系统会根据窗口的内容是否存在任何可滚动其内容的布局视图来自动选择其中一种模式。 如果存在这样的视图,窗口将进行尺寸调整,前提是可通过滚动在较小区域内看到窗口的所有内容。
adjustResize 始终调整 Activity 主窗口的尺寸来为屏幕上的软键盘腾出空间。
adjustPan 不调整 Activity 主窗口的尺寸来为软键盘腾出空间, 而是自动平移窗口的内容,使当前焦点永远不被键盘遮盖,让用户始终都能看到其输入的内容。 这通常不如尺寸调整可取,因为用户可能需要关闭软键盘以到达被遮盖的窗口部分或与这些部分进行交互。
adjustNoting 软键盘弹出时,主窗口Activity不会做出任何响应。
需要注意下,我们用的比较多的是adjustPan 和 adjustResize
如果没有使用ScrollView,adjustPan可以把EditText顶到顶部,但AdjustResie会把EditText完全遮住,也就是界面不变,也就是说,一般使用adjuestResize都需要在布局中添加一个ScrollView。

二、遮挡一部分

在模拟器上,需要滑动10dp就可以解决了,所以问题就出现了,如果滑动40DP,很明显对那些只需要滑动10DP的设备来说会导致Edittext和软键盘间隔很远,滑动没必要的高度。
网上说出现这种情况是只要设置背景色就会遮一部分,不设置就没问题。但我发现并不是,而是字体,如果字体设置很小,或者设置padding的时候,就会出现如下图的情况:
这里写图片描述
我们可以理解,软键盘的顶部始终是和文字或光标的下基准线是对齐的。不知道Google是出于什么样的考虑这样设置的,通常理解都是软键盘顶部和EditText下基准线对齐的。
具体解决办法是:
mContentRootLl.getViewTreeObserver().addOnGlobalLayoutListener(this);

mContentRootLl.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                Rect rect = new Rect();
                //获取root在窗体的可视区域
                mContentRootLl.getWindowVisibleDisplayFrame(rect);
                int rootHeight = mContentRootLl.getRootView().getHeight();
                int rootVisibleHeight = rect.bottom - rect.top;
                int rootInvisibleHeight = rootHeight - rootVisibleHeight;
                //若不可视区域高度大于root在窗体的总共高度的四分之一,则显示软键盘
                if (rootInvisibleHeight > rootHeight / 4) {
                    int[] location = new int[2];
                    mEditAddressTagLl.getLocationInWindow(location);
                    //计算root滚动高度,使mContentRootLl在可见区域
                    int scrollHeight = (location[1] + mEditAddressTagLl.getHeight()) - rect.bottom;
                    mContentRootLl.scrollTo(0, scrollHeight); //注释2
                } else {
                    //收起软键盘
                    mContentRootLl.scrollTo(0, 0);
                }
            }
        });

通过以上方法就可以解决。解决后的效果:
这里写图片描述
注释2的地方可以设置任意值,比如希望输入框置顶等等。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值