Android WebView输入框被档问题升级解析

前言

主要是issue 5497这个问题。然后可能有些朋友觉得,这篇文章没能解决他的问题,或者说按照我的代码去写又会出现新的问题。这说明没有能理解这篇文章写的内容,我只是举了一个自己碰到的场景,然后去分析,为什么会这样,并用一些源码告诉你为什么这样写的能解决。但是并不是所有的场景去套这个代码都是正常的,不过如果你理解其中的一些原理的话,你至少能有个方向知道该从何下手去解决你自己碰到的场景。

如果看不懂没关系,我这次讲慢点,再去慢慢分析更多的场景,但是有一点要记住,我对这个问题的处理不是万金油,你必须要有一定的理解,知道一个方向,再去解决自己碰到的场景,不要直接套代码。 这里分析的问题就是issue 5497这个问题。

issue 5497问题

我们再简单回顾一下这个问题,原生的软键盘和输入框的冲突,直接设置window的softInputMode就能解决,这个很简单。但是如果输入框是webview内部H5的输入框的情况下pan会失效,只能用resize。并且,如果是这个window是概念上全屏的情况下(设置全屏的方式很多),resize也会失效。

我上一篇文章中,我碰到的问题的场景是: 一个Dialog,里面的根页面设置了沉浸模式,根布局下有一个webview,webview中有个输入框,点击输入框时弹出软键盘会挡住输入框。

我们先分析,为什么会挡住输入框?因为默认的softInputMode在正常情况下会顶起输入框,但是webview会失效,那我们就把softInputMode设成SOFT_INPUT_ADJUST_RESIZE

然后发现没效果,为什么没效果?因为我的Dialog是全屏的,并且设置了沉浸模式,所以符合了全屏情况下resize也会失效这个条件。注意这个全屏可以理解成指的是概念上的全屏,不是我们视觉效果上的全屏,也就是这时去设置marginTop,通过这些方法去改变视觉上不是全屏是不会有效果的。

我们的思路就是破解让这个window变成非全屏。 从上一篇文章可以看出,我们用的方法是设置fitSystemWindows,通过fitSystemWindows设置为true,来破解沉浸模式导致的全屏效果,原理是什么?通过上一篇文章知道,原理是设置一个安全距离,但是这个安全距离会导致你的window被压缩,所以我们要重写view的fitSystemWindows方法设置安全距离去防止window被压缩

@Override
protected boolean fitSystemWindows(Rect insets) {
 insets.top = 0;
 return super.fitSystemWindows(insets);
}

而这个问题的解决思路是通过设置fitSystemWindows去打破全屏这个条件,从而使SOFT_INPUT_ADJUST_RESIZE能对webview生效。 这是重点的一步,后续的操作都是为了处理fitSystemWindows所带来的影响。

布局顶起后距离软键盘有一定距离

一般我们的布局顶起后底部也是紧贴软键盘,有的朋友可能会说,为什么我也这样做了,但是我webview布局被软键盘顶起之后距离软键盘会存在一部分的间距。

如果你不知道这个问题,说明对softInputMode不太理解,虽然我个人对这个理解也不是很深,但是如果你能使用SOFT_INPUT_ADJUST_PAN的话,就一定不会出现这个问题,但是用SOFT_INPUT_ADJUST_RESIZE的话,就会在某些布局中有这个问题,可惜上面说了,webview对SOFT_INPUT_ADJUST_PAN无效。

这是为什么呢?因为简单来说SOFT_INPUT_ADJUST_PAN是顶起你的输入框,而SOFT_INPUT_ADJUST_RESIZE会把window给顶起来。所以如果你是window全屏并且webview也是全屏的情况就不会遇到这个问题(这里其实也就高度影响,宽度不影响),但如果你是window中的webview距离window的底部有一定的距离,这时候用SOFT_INPUT_ADJUST_RESIZE顶起来就会和输入法有一段距离。

那这个问题要如何解决,这个解决的方法很多,比如通过逻辑手段,或者调整webview大小之类的,这个就没什么好说的了。

Activity的webview输入框被挡

上一篇文章包括上面有讲我在Dialog中的webview的场景的解决方案。有的朋友会说我activity的webview也是这样的,但是按照你这个代码写进去没有效果,我明明也给window设置了SOFT_INPUT_ADJUST_RESIZE,也给view设置了setFitsSystemWindows,也重写了fitSystemWindows方法设置top,但是没效果。

这就说明你还没明白为什么会出现这个问题,你只是希望随便去找个文章拷代码下来用,代码有用就觉得这个作者牛,代码没效果就觉得这个作者傻。好,哪怕你是不看为什么,只想考代码,套到你使用的地方没效果,那为何不问问为什么没效果,你可以在评论区留言,说你是什么样的场景,使用这个代码没效果。写一两句留言对你来说也并不耗多少时间,我只是觉得,解决问题,需要知道一个方向,不能一味的只想抄答案,这样去解决问题是很耗费时间的,而且这样解决问题也可能会出现其它的问题。

有点扯远了,话说回来,为什么上面的代码对Activity可能没效果。如果认真看都知道,我说了造成SOFT_INPUT_ADJUST_RESIZE失效的原因是全屏,而我上面Dialog的场景,造成全屏的操作是设置了沉浸模式,所以setFitsSystemWindows是为了处理沉浸模式导致全屏的情况。而你的Activity的全屏,不一定是沉浸模式造成的,所以你使用setFitsSystemWindows会无效。

还看不懂没关系,再举个例子。你给你的activity设置Fullscreen的主题theme也会导致全屏,这时候给window设置SOFT_INPUT_ADJUST_RESIZE无效,我们的思路是如何去破解Fullscreen这个主题造成的全屏。我们可以动态去概念theme,行不行?当然可以,但是这个时机要写对。

我们也可以用window.clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN)去破解全屏的效果嘛。但是这个clearFlags如果对你的需求造成了影响,你还要通过其它方法去消除这个影响,这种就具体分析具体解决了,没有标准的答案。

总结

写这篇文章主要是想说明,这个webview被输入法挡住的问题,这个issue 5497,是一个比较麻烦的问题,它不是光靠随便在网上去抄个代码就能解决的。包括你可能会去通过监听输入法的弹出去计算滚动的高度,这种方法理论上是不难,实际去开发也是要做一些细节处理和兼容的。

这篇文章没有贴多少代码,主要讲一个解决问题的思路。要去理解这个问题是为什么发生的,知道一个方向,才能去更好的解决问题,你可以不按照我的代码去写,但是你知道解决问题的方向后,你甚至能自己通过适合自己业务的逻辑代码去解决你的问题。

我不保证我对整个问题的理解是完全正确的,但是如果有大佬觉得我的理解有问题,可以指出,我也希望能这样,这样反而让我印象更深刻。但是如果有人想不了解这些内容的情况下通过去找别人的代码去碰运气来解决问题,那我也只能祝你好运。

作者:流浪汉kylin

%s 个评论

要回复文章请先登录注册