Android?WebView軟鍵盤遮擋輸入框方案詳解
背景
筆者在使用 WebView 加載含有輸入框的 H5 頁(yè)面時(shí),點(diǎn)擊輸入框后,輸入框會(huì)被軟鍵盤遮擋住,無(wú)法看到輸入的內(nèi)容,這很影響用戶體驗(yàn)。
筆者想著這種業(yè)務(wù)場(chǎng)景比較常見,遂上網(wǎng)搜索一番,果不其然,有不少同志遇到這個(gè)問(wèn)題,想來(lái)這個(gè)問(wèn)題很好解決了。筆者一一嘗試了同志們提供的解決方案,結(jié)果要不是沒有作用,要不是效果不太滿意,只好自己另辟蹊徑了。
注:在筆者的業(yè)務(wù)場(chǎng)景中,App是全屏的,即沒有頂部的系統(tǒng)欄,也沒有底部的導(dǎo)航欄,所以筆者的解決方案,可能不適用于其他場(chǎng)景。
紀(jì)實(shí)
方案
好的,重新梳理下遇到的問(wèn)題,目前的問(wèn)題是:用戶無(wú)法看到輸入框里的內(nèi)容,那么我們可以先讓用戶看到輸入框里的內(nèi)容。
筆者想到了第一種方案:**輸入框被軟鍵盤遮擋后,在軟鍵盤輸入時(shí),可以在 H5 頁(yè)面頂部實(shí)時(shí)顯示輸入框里的內(nèi)容。**本方案解決了輸入框被軟鍵盤遮擋后看不到輸入內(nèi)容的問(wèn)題,但是沒有解決輸入框被軟鍵盤遮擋的問(wèn)題,此方案一定程度上提升了用戶體驗(yàn),不過(guò)筆者認(rèn)為本方案不是很完美,繼續(xù)思考其他方案。
最后筆者想到了第二種方案,大體思路如下:
- 筆者的業(yè)務(wù)場(chǎng)景,App是全屏的,所以整個(gè) WebView 也是全屏的,
- 在點(diǎn)擊 H5 頁(yè)面的輸入框時(shí),H5 獲取當(dāng)前輸入框左下角的 Y 坐標(biāo),然后把左下角的 Y 坐標(biāo)通知到 Android 原生,
- Android 原生獲取軟鍵盤頂部的 Y 坐標(biāo)與輸入框左下角的 Y 坐標(biāo)進(jìn)行比較,如果小于左下角的 Y 坐標(biāo),則認(rèn)為此時(shí)輸入框被軟鍵盤遮擋,需要將 WebView 向上滾動(dòng)相應(yīng)的距離以顯示出來(lái)輸入框,否則判斷 WebView 當(dāng)前的滾動(dòng)距離是否為 0,如果不為 0 則取當(dāng)前距離的負(fù)值作為滾動(dòng)距離,否則就不滾動(dòng)。
上述方案的文字描述可能比較繞,我們可以看下面的流程圖跟上思路:
實(shí)現(xiàn)
接下來(lái)筆者根據(jù)上面的方案二進(jìn)行代碼上的具體實(shí)現(xiàn):
首先是獲取輸入框左下角的 Y 坐標(biāo),這一步如果讓前端來(lái)實(shí)現(xiàn)的話,是比較容易的,不過(guò)筆者認(rèn)為方案二是一種比較通用的解決方案,可以提取出來(lái)作為二方庫(kù)來(lái)使用,如果讓其他使用二方庫(kù)項(xiàng)目組的前端同志也來(lái)實(shí)現(xiàn)一次的話就比較麻煩了,所以在這一步,筆者選擇了在 Android 端注入 JS 的方案:
ready(); document.addEventListener("readystatechange", function () { var readyState = document.readyState; if (readyState !== "loading") { console.log(readyState); ready(); } }); document.addEventListener("DOMContentLoaded", function () { console.log("DOMContentLoaded"); ready(); }); function ready() { document.body.addEventListener("DOMNodeInserted", function () { webInput(); }); webInput(); } function webInput() { var input = document.querySelectorAll("input") || []; console.log("input -> " + input.length); if (input.length === 0) { return; } input.forEach(function (value) { var type = value.getAttribute("type"); console.log("type -> " + type); if (type === null || type === "number" || type === "search" || type === "password" || type === "tel" || type === "email" || type === "url" || type === "text") { value.removeEventListener("click", webInput2Android); value.removeEventListener("focus", webInput2Android); value.addEventListener("click", webInput2Android); value.addEventListener("focus", webInput2Android); } }); } function webInput2Android() { console.log("webInput2Android"); var offset = getOffset(this); var x = offset.x; var y = offset.y; console.log("x:y --> " + x + ":" + y); var width = this.offsetWidth; var height = this.offsetHeight; console.log("w:h --> " + width + ":" + height); // Send to Android } function getOffset (el) { var box = el.getBoundingClientRect(); return { x: box.left + window.pageXOffset - document.documentElement.clientLeft, y: box.top + window.pageYOffset - document.documentElement.clientTop } }
在 JS 中通過(guò)監(jiān)聽輸入框的點(diǎn)擊事件,在點(diǎn)擊時(shí)獲取輸入框左上角的坐標(biāo)和輸入框的寬高,間接算出輸入框左下角的坐標(biāo),然后通知到 Android 原生:
public void run() { Activity activity = mActivityReference.get(); WebView webView = mWebViewReference.get(); if (activity == null || webView == null) { return; } // JS 傳入的輸入框左下角 Y 坐標(biāo) int bottom = mWebInput.getBottom(); // 獲取軟鍵盤頂部的 Y 坐標(biāo) int keyboardTop = KeyboardHelper.getKeyboardTop(activity); // WebView 當(dāng)前滾動(dòng)的距離 int scrollY = webView.getScrollY(); // 判斷軟鍵盤是否彈出 if (keyboardTop != -1) { // 判斷輸入框是否被軟鍵盤遮擋 if (bottom >= keyboardTop) { // 計(jì)算滾動(dòng)距離 int diff = bottom - keyboardTop - scrollY; // 滾動(dòng) WebView diff + mDistance 距離,mDistance 默認(rèn) 50, // diff + mDistance:即軟鍵盤距離輸入框底部 50 距離 webView.assistWebKeyboard(scrollY, diff + mDistance); } else { // 判斷 WebView 是否有滾動(dòng) if (scrollY != 0) { // 滾動(dòng) WebView webView.assistWebKeyboard(scrollY, -scrollY); } } } }
以上代碼實(shí)現(xiàn)方案二中第三步,首先獲取 JS 傳入的輸入框左下角 Y 坐標(biāo),其次獲取軟鍵盤頂部的 Y 坐標(biāo),然后獲取 WebView 當(dāng)前滾動(dòng)的距離,接下來(lái)根據(jù)軟鍵盤頂部的 Y 坐標(biāo)判斷軟鍵盤是否彈出,在軟鍵盤彈出的情況下,判斷輸入框左下角 Y 坐標(biāo)是否大于等于軟鍵盤頂部 Y 坐標(biāo):
- 如果大于等于,則認(rèn)為輸入框被軟鍵盤遮擋,此時(shí)計(jì)算出 WebView 需要滾動(dòng)多長(zhǎng)的距離,輸入框才能被顯示出來(lái),最后調(diào)用
assistWebKeyboard
方法滾動(dòng) WebView - 如果小于,則認(rèn)為輸入框沒有被軟鍵盤遮擋,此時(shí)判定 WebView 之前是否有滾動(dòng),如果有滾動(dòng)距離,則計(jì)算滾動(dòng)距離為當(dāng)前滾動(dòng)距離的負(fù)值,最后調(diào)用
assistWebKeyboard
方法滾動(dòng) WebView
至此完結(jié)。
總結(jié)
本文提供了一種新的解決 WebView 輸入框被軟鍵盤遮擋的思路,不過(guò)這種思路也有它的局限性,目前來(lái)看僅適用于全屏的 WebView 中,后續(xù)筆者再想到其他方案時(shí),另寫一篇紀(jì)實(shí)續(xù)集吧。
到此這篇關(guān)于Android WebView軟鍵盤遮擋輸入框方案詳解的文章就介紹到這了,更多相關(guān)android 軟鍵盤遮擋輸入框內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Android WebView輸入框被檔問(wèn)題升級(jí)解析
- 淺談Android開發(fā)Webview的Loading使用效果
- Android?webView加載數(shù)據(jù)時(shí)內(nèi)存溢出問(wèn)題及解決
- Android?WebView預(yù)渲染介紹
- Android WebView如何判斷是否滾動(dòng)到底部
- Android WebView控件基本使用示例
- Android WebView基礎(chǔ)應(yīng)用詳解
- Android WebView實(shí)現(xiàn)全屏播放視頻
- Android?WebView緩存機(jī)制優(yōu)化加載慢問(wèn)題
相關(guān)文章
Android XRecyclerView最簡(jiǎn)單的item點(diǎn)擊事件處理
這篇文章主要為大家詳細(xì)介紹了Android XRecyclerView最簡(jiǎn)單的item點(diǎn)擊事件處理,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-12-12基于Android實(shí)現(xiàn)ListView圓角效果
這篇文章主要為大家詳細(xì)介紹了基于Android實(shí)現(xiàn)ListView圓角效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-06-06Android動(dòng)畫之漸變動(dòng)畫(Tween Animation)詳解 (漸變、縮放、位移、旋轉(zhuǎn))
這篇文章主要介紹了Android動(dòng)畫之漸變動(dòng)畫(Tween Animation)用法,結(jié)合實(shí)例形式詳細(xì)分析了Android漸變動(dòng)畫Tween Animation實(shí)現(xiàn)漸變,縮放,位移,旋轉(zhuǎn)等技巧,需要的朋友可以參考下2016-01-01Android如何動(dòng)態(tài)調(diào)整應(yīng)用字體大小詳解
這篇文章主要給大家介紹了關(guān)于Android如何動(dòng)態(tài)調(diào)整應(yīng)用字體大小的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2018-05-05淺談Android IPC機(jī)制之Binder的工作機(jī)制
IPC機(jī)制即為跨進(jìn)程通信,是inter-Process Communication的縮寫。是指兩個(gè)進(jìn)程之間進(jìn)行通信。在說(shuō)進(jìn)程通信之前,我們的弄明白什么是線程,什么是進(jìn)程。進(jìn)程和線程是兩個(gè)截然不同的概念。本文將介紹Android IPC機(jī)制之Binder的工作機(jī)制。2021-06-06Android開發(fā)中調(diào)用系統(tǒng)相冊(cè)上傳圖片到服務(wù)器OPPO等部分手機(jī)上出現(xiàn)短暫的顯示桌面問(wèn)題的解決方法
這篇文章主要介紹了Android開發(fā)中調(diào)用系統(tǒng)相冊(cè)上傳圖片到服務(wù)器OPPO等部分手機(jī)上出現(xiàn)短暫的顯示桌面問(wèn)題的解決方法,需要的朋友可以參考下2016-12-12Flutter進(jìn)階之實(shí)現(xiàn)動(dòng)畫效果(九)
這篇文章主要為大家詳細(xì)介紹了Flutter進(jìn)階之實(shí)現(xiàn)動(dòng)畫效果的第九篇,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-08-08Android開發(fā)之Button事件實(shí)現(xiàn)與監(jiān)聽方法總結(jié)
這篇文章主要介紹了Android開發(fā)之Button事件實(shí)現(xiàn)與監(jiān)聽方法,結(jié)合實(shí)例形式總結(jié)分析了Android開發(fā)中Button事件的兩種實(shí)現(xiàn)方法以及針對(duì)Button控件的幾種常用監(jiān)聽方法,需要的朋友可以參考下2016-01-01Android關(guān)于WebView中無(wú)法定位的問(wèn)題解決
本篇文章主要介紹了Android關(guān)于WebView中無(wú)法定位的問(wèn)題解決,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-10-10Android數(shù)據(jù)緩存框架內(nèi)置ORM功能使用教程
這篇文章主要為大家介紹了Android數(shù)據(jù)緩存框架內(nèi)置ORM功能使用教程,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-09-09