关于ios的webview中键盘弹出影响布局的解决方案

如果你在开发ios中的webview界面的时候会遇到以下问题,并且没有一个很好的解决方案的时候,可以继续阅读以下的文章,如果已经有了比较好的解决方案,我希望你可以继续阅读以下的内容,并给与我真诚的建议,谢谢!!!


问题

  1. 使用header container footer 三个absolute布局的时候,当键盘弹出的时候,header消失在视图外面
  2. 当键盘弹出的时候、遮住了最底层的输入框
  3. 当键盘弹出的时候、输入框出现在视图外,无法有效的观测到自己的输入

本文将会对这些问题进行讲解,给出一套比较通用的解决方案。帮助大家进行ios中webview的开发
ps: 我们将会搭配cordova进行使用,因为webview依赖原生开发,如果你们的项目不使用cordova,请找你们的原生给出一些我们将会用到的cordova插件的替代方案,请不要自行背锅。这样不利于项目的正常开发。

问题1

我们问题1在说什么?在移动端做布局的时候,我们很多的时候会给body一个

height:100%;
overflow:hidden;

的设置,这样会比较方便我们后面的布局,而此后的布局,大致可以分成三份
header
container
footer

这三块都使用absolute绝对布局来进行处理,可以控制,我们的header跟footer能够永远出现在我们的视线之内,header footer上通常有部分操作按键帮助我们执行一些操作,根据情况footer也经常不进行使用

如图

image

而当我们的键盘弹出的时候,在ios可能会出现以下的情况
image

可以看到,我们的header被顶出了视图之外,这样实际的操作体验是会不如人意的。怎么处理这种问题呢?
如果你使用的是cordova这些,那么你可以借助一些插件,我们使用的是ionic-plugin-keyboard,虽然是个ionic的插件,但是在vue项目中也能使用。。。
键盘插件
使用
Keyboard.disableScroll
设置为true,这样我们的webview就不会再进行滚动了,那么当键盘弹出的时候,则会是
image

这样就可以有效的解决header超出屏幕的问题了。
但是很明显,我们在这里也可以看到一个新的问题,那就是keyboard遮住了footer部分。这也是我们的第二个问题

问题2

来解决keyboard遮住了footer部分这个问题呢?其实思路也很简单,一般来说,我们的footer都是固定到底部的,他会有代码

bottom:0px;

而其相对位置,一般是body或者#app这种与body等高的元素,其高度为一屏幕。
那么我们只要让我们的body减小到原本的高度,减去键盘高度那么我们的footer自然就会在键盘上面了。
ps:这套方案不可以同时作用于安卓上面存在问题
那么代码设计就很简单了。
键盘弹出事件,我们可以通过onresize或者上面提到的cordova的键盘插件进行监听,或者让原生给出桥接。
这部分的代码是比较好处理的。
我们使用window.innerHeight获取初始的高度
使用document.body.style.height改变body高度

但是也存在问题
在ios上,有的时候,具体处罚条件不明,不管是resize还是cordova都有可能在一次聚焦触发多次事件,而第二次的事件中获取的键盘高度是不正确的,因此可能你需要一个节流处理,可以使用rxjs或者loadsh的节流行数进行处理

而为了获得更佳的用户体验,我们就有了问题三。

问题3

我们当然希望自己在输入的时候,能够始终拥有最佳的视图效果,也就是,我们输入的内容,始终在我们的视野范围之内,而经过前面哪一步,有的时候键盘弹出的时候我们的输入框是不会出现在我们的视野范围之内的
此时我们的聚焦区域不是footer而位于可滚动的container之内,因为body的高度缩小,就有可能导致我们container中的输入框出现在视图之外。
怎么解决呢?首先我们给出一个解决的目标
我们希望当聚焦键盘弹出的时候,输入框位置始终位于header下方20px的位置上
其中 20px 这个值可以根据产品喜好进行设置,且,存在一些情况你并不会希望其位置为20px,根据具体需求来设定,但是大致方向不变化。
那么我们怎么才能做到这样呢?比较愚蠢的做法是,监听每个input或者textare的focus事件,然后给定一个死值,但是这样代码十分的冗余,可维护性低下,而如果你知道了document.activeElement,通过这个元素来获取当前聚焦的元素,结合问题2中的解决方案,我们可以在键盘弹出事件中进行处理,获取到当前聚焦元素,再判断他是哪个元素,从而实现滚动。

整体处理方式我们使用了vuex这种store工具进行处理,键盘聚焦的时候设置state.common中的变量showKeyborad为true,在我们有input元素的组件中watch这个store值,再判断是哪个元素聚焦了,从而给出了滚动值。

这个方案也是我们第一版的处理方案,所以很明显,我们还有第二版~因为我们知道了另外一个属性
offsetParent
根据这个属性,我们可以知道当前元素的定位父元素

定位父级offsetParent的定义是:与当前元素最近的经过定位(position不等于static)的父级元素,主要分为下列几种情况

而元素的另外一个属性offsetTop则是当前元素距离定位父元素的位置。
为什么我们要使用这个呢?
因为在大部分的情况下,我们往往会使用组件库进行开放,而不是自己手写input,而对于大部分的组件库的设计来说,input组件的最外层都是一些包裹元素,其真实的表单元素并不在最外层,这一点我们可以在外面观测到。
那么我们的设计思路就很简单了。
因为我们要求滚动的是中间这个部分,如下图

image

而对于我们的整体dom结构往往是

body
    #app
        .container
            .a
                .b
                    .input-wrapper1
                        .inpuy-wrapperx
                            input

很明显,我们的滚动区域,就是 .container区域
其一般有css

top:headerHeight;
bottom:footerHeight;

那么实际上只需要我们逐步计算,从当前聚焦元素到container的offsetTop那么我们就知道应该让container滚动多少距离,从而实现滚动到我们需要的位置上去。
具体参考demo
核心代码

handleTestInputFocus () {
  let activeElement = document.activeElement
  let offsetTop = activeElement.offsetTop
  let offsetParent = activeElement.offsetParent
  if (activeElement === document.body) {
    return
  }
  while (offsetParent.id !== this.wrapperId && offsetParent !== document.body) {
    offsetTop += offsetParent.offsetTop
    offsetParent = offsetParent.offsetParent
  }
  const viewTop = 20 // 不应该让光标紧贴header 这样体验依旧不好
  document.getElementById(this.wrapperId).scrollTop = offsetTop - viewTop
}

注意在demo中我使用了focus时间来代替键盘弹出事件,这样会比较好进行观测。
所以会有一句对activeElement为body的处理。
此外,最外层一定要保证没margin,padding这些
demo地址为
Demo
切换到focus-scroll查看demo
但是这里还有一点需要注意的是,在ios的webview中,出现光标浮动在header上的情况,这种时候需要监听滚动事件,在滚动的时候失焦
如果你有不需要失焦就能解决这个问题的办法,希望可以联系我,教我一下谢谢!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,591评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,448评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,823评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,204评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,228评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,190评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,078评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,923评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,334评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,550评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,727评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,428评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,022评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,672评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,826评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,734评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,619评论 2 354

推荐阅读更多精彩内容