Android?WebView軟鍵盤遮擋輸入框方案詳解
背景
筆者在使用 WebView 加載含有輸入框的 H5 頁面時(shí),點(diǎn)擊輸入框后,輸入框會(huì)被軟鍵盤遮擋住,無法看到輸入的內(nèi)容,這很影響用戶體驗(yàn)。
筆者想著這種業(yè)務(wù)場(chǎng)景比較常見,遂上網(wǎng)搜索一番,果不其然,有不少同志遇到這個(gè)問題,想來這個(gè)問題很好解決了。筆者一一嘗試了同志們提供的解決方案,結(jié)果要不是沒有作用,要不是效果不太滿意,只好自己另辟蹊徑了。
注:在筆者的業(yè)務(wù)場(chǎng)景中,App是全屏的,即沒有頂部的系統(tǒng)欄,也沒有底部的導(dǎo)航欄,所以筆者的解決方案,可能不適用于其他場(chǎng)景。
紀(jì)實(shí)
方案
好的,重新梳理下遇到的問題,目前的問題是:用戶無法看到輸入框里的內(nèi)容,那么我們可以先讓用戶看到輸入框里的內(nèi)容。
筆者想到了第一種方案:**輸入框被軟鍵盤遮擋后,在軟鍵盤輸入時(shí),可以在 H5 頁面頂部實(shí)時(shí)顯示輸入框里的內(nèi)容。**本方案解決了輸入框被軟鍵盤遮擋后看不到輸入內(nèi)容的問題,但是沒有解決輸入框被軟鍵盤遮擋的問題,此方案一定程度上提升了用戶體驗(yàn),不過筆者認(rèn)為本方案不是很完美,繼續(xù)思考其他方案。
最后筆者想到了第二種方案,大體思路如下:
- 筆者的業(yè)務(wù)場(chǎng)景,App是全屏的,所以整個(gè) WebView 也是全屏的,
- 在點(diǎn)擊 H5 頁面的輸入框時(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)的距離以顯示出來輸入框,否則判斷 WebView 當(dāng)前的滾動(dòng)距離是否為 0,如果不為 0 則取當(dāng)前距離的負(fù)值作為滾動(dòng)距離,否則就不滾動(dòng)。
上述方案的文字描述可能比較繞,我們可以看下面的流程圖跟上思路:

實(shí)現(xiàn)
接下來筆者根據(jù)上面的方案二進(jìn)行代碼上的具體實(shí)現(xiàn):
首先是獲取輸入框左下角的 Y 坐標(biāo),這一步如果讓前端來實(shí)現(xiàn)的話,是比較容易的,不過筆者認(rèn)為方案二是一種比較通用的解決方案,可以提取出來作為二方庫來使用,如果讓其他使用二方庫項(xiàng)目組的前端同志也來實(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 中通過監(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)的距離,接下來根據(jù)軟鍵盤頂部的 Y 坐標(biāo)判斷軟鍵盤是否彈出,在軟鍵盤彈出的情況下,判斷輸入框左下角 Y 坐標(biāo)是否大于等于軟鍵盤頂部 Y 坐標(biāo):
- 如果大于等于,則認(rèn)為輸入框被軟鍵盤遮擋,此時(shí)計(jì)算出 WebView 需要滾動(dòng)多長(zhǎng)的距離,輸入框才能被顯示出來,最后調(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 輸入框被軟鍵盤遮擋的思路,不過這種思路也有它的局限性,目前來看僅適用于全屏的 WebView 中,后續(xù)筆者再想到其他方案時(shí),另寫一篇紀(jì)實(shí)續(xù)集吧。
到此這篇關(guān)于Android WebView軟鍵盤遮擋輸入框方案詳解的文章就介紹到這了,更多相關(guān)android 軟鍵盤遮擋輸入框內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Android Studio中導(dǎo)入JNI生成的.so庫的實(shí)現(xiàn)方法
這篇文章主要介紹了Android Studio中導(dǎo)入JNI生成的.so庫的實(shí)現(xiàn)方法的相關(guān)資料,這里不僅提供實(shí)現(xiàn)方案并提供了實(shí)現(xiàn)的方法,需要的朋友可以參考下2017-07-07
Android項(xiàng)目中使用Eclipse導(dǎo)出jar文件的操作方法
文章講述了如何使用Eclipse將Android項(xiàng)目打包成jar文件,并詳細(xì)解答了在打包過程中遇到的問題,如如何處理依賴的jar或library,以及如何解決在其他項(xiàng)目中引用時(shí)出現(xiàn)的NoClassDefFoundError錯(cuò)誤2025-02-02
Android手機(jī)聯(lián)系人帶字母索引的快速查找
這篇文章主要為大家詳細(xì)介紹了Android手機(jī)聯(lián)系人帶字母索引的快速查找實(shí)現(xiàn)方法,感興趣的小伙伴們可以參考一下2016-03-03
Android實(shí)現(xiàn)圖片自動(dòng)切換功能(實(shí)例代碼詳解)
這篇文章主要介紹了Android實(shí)現(xiàn)圖片自動(dòng)切換功能,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-02-02
Android基礎(chǔ)開發(fā)小案例之短信發(fā)送器
這篇文章主要為大家詳細(xì)介紹了Android基礎(chǔ)開發(fā)小案例之短信發(fā)送器的具體實(shí)現(xiàn)代碼,感興趣的小伙伴們可以參考一下2016-05-05
Flutter簡(jiǎn)潔實(shí)用的圖片編輯器的實(shí)現(xiàn)
本文主要介紹了Flutter簡(jiǎn)潔實(shí)用的圖片編輯器的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-02-02

