網站首頁 編程語言 正文
背景
筆者在使用 WebView 加載含有輸入框的 H5 頁面時,點擊輸入框后,輸入框會被軟鍵盤遮擋住,無法看到輸入的內容,這很影響用戶體驗。
筆者想著這種業務場景比較常見,遂上網搜索一番,果不其然,有不少同志遇到這個問題,想來這個問題很好解決了。筆者一一嘗試了同志們提供的解決方案,結果要不是沒有作用,要不是效果不太滿意,只好自己另辟蹊徑了。
注:在筆者的業務場景中,App是全屏的,即沒有頂部的系統欄,也沒有底部的導航欄,所以筆者的解決方案,可能不適用于其他場景。
紀實
方案
好的,重新梳理下遇到的問題,目前的問題是:用戶無法看到輸入框里的內容,那么我們可以先讓用戶看到輸入框里的內容。
筆者想到了第一種方案:**輸入框被軟鍵盤遮擋后,在軟鍵盤輸入時,可以在 H5 頁面頂部實時顯示輸入框里的內容。**本方案解決了輸入框被軟鍵盤遮擋后看不到輸入內容的問題,但是沒有解決輸入框被軟鍵盤遮擋的問題,此方案一定程度上提升了用戶體驗,不過筆者認為本方案不是很完美,繼續思考其他方案。
最后筆者想到了第二種方案,大體思路如下:
- 筆者的業務場景,App是全屏的,所以整個 WebView 也是全屏的,
- 在點擊 H5 頁面的輸入框時,H5 獲取當前輸入框左下角的 Y 坐標,然后把左下角的 Y 坐標通知到 Android 原生,
- Android 原生獲取軟鍵盤頂部的 Y 坐標與輸入框左下角的 Y 坐標進行比較,如果小于左下角的 Y 坐標,則認為此時輸入框被軟鍵盤遮擋,需要將 WebView 向上滾動相應的距離以顯示出來輸入框,否則判斷 WebView 當前的滾動距離是否為 0,如果不為 0 則取當前距離的負值作為滾動距離,否則就不滾動。
上述方案的文字描述可能比較繞,我們可以看下面的流程圖跟上思路:
實現
接下來筆者根據上面的方案二進行代碼上的具體實現:
首先是獲取輸入框左下角的 Y 坐標,這一步如果讓前端來實現的話,是比較容易的,不過筆者認為方案二是一種比較通用的解決方案,可以提取出來作為二方庫來使用,如果讓其他使用二方庫項目組的前端同志也來實現一次的話就比較麻煩了,所以在這一步,筆者選擇了在 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 中通過監聽輸入框的點擊事件,在點擊時獲取輸入框左上角的坐標和輸入框的寬高,間接算出輸入框左下角的坐標,然后通知到 Android 原生:
public void run() { Activity activity = mActivityReference.get(); WebView webView = mWebViewReference.get(); if (activity == null || webView == null) { return; } // JS 傳入的輸入框左下角 Y 坐標 int bottom = mWebInput.getBottom(); // 獲取軟鍵盤頂部的 Y 坐標 int keyboardTop = KeyboardHelper.getKeyboardTop(activity); // WebView 當前滾動的距離 int scrollY = webView.getScrollY(); // 判斷軟鍵盤是否彈出 if (keyboardTop != -1) { // 判斷輸入框是否被軟鍵盤遮擋 if (bottom >= keyboardTop) { // 計算滾動距離 int diff = bottom - keyboardTop - scrollY; // 滾動 WebView diff + mDistance 距離,mDistance 默認 50, // diff + mDistance:即軟鍵盤距離輸入框底部 50 距離 webView.assistWebKeyboard(scrollY, diff + mDistance); } else { // 判斷 WebView 是否有滾動 if (scrollY != 0) { // 滾動 WebView webView.assistWebKeyboard(scrollY, -scrollY); } } } }
以上代碼實現方案二中第三步,首先獲取 JS 傳入的輸入框左下角 Y 坐標,其次獲取軟鍵盤頂部的 Y 坐標,然后獲取 WebView 當前滾動的距離,接下來根據軟鍵盤頂部的 Y 坐標判斷軟鍵盤是否彈出,在軟鍵盤彈出的情況下,判斷輸入框左下角 Y 坐標是否大于等于軟鍵盤頂部 Y 坐標:
- 如果大于等于,則認為輸入框被軟鍵盤遮擋,此時計算出 WebView 需要滾動多長的距離,輸入框才能被顯示出來,最后調用
assistWebKeyboard
方法滾動 WebView - 如果小于,則認為輸入框沒有被軟鍵盤遮擋,此時判定 WebView 之前是否有滾動,如果有滾動距離,則計算滾動距離為當前滾動距離的負值,最后調用
assistWebKeyboard
方法滾動 WebView
至此完結。
總結
本文提供了一種新的解決 WebView 輸入框被軟鍵盤遮擋的思路,不過這種思路也有它的局限性,目前來看僅適用于全屏的 WebView 中,后續筆者再想到其他方案時,另寫一篇紀實續集吧。
原文鏈接:https://juejin.cn/post/7105765986120237087
- 上一篇:C++鏈式二叉樹深入分析_C 語言
- 下一篇:C語言深入探索遞歸的特點_C 語言
相關推薦
- 2023-01-19 C#實現身份證驗證功能的示例代碼_C#教程
- 2022-08-04 深入理解pytorch庫的dockerfile_python
- 2022-07-08 教你利用python的matplotlib(pyplot)繪制折線圖和柱狀圖_python
- 2022-05-11 解決 IntelliJ IDEA 中 .propertise 文件保存后中文亂碼
- 2022-05-22 iOS實現背景滑動效果_IOS
- 2022-09-03 詳解Docker鏡像的基本操作方法_docker
- 2023-04-09 python實現數組平移K位問題_python
- 2022-04-15 玩數據必備Python庫之numpy使用詳解_python
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支