android軟鍵盤遮擋WebView中input的解決方案
阿新 • • 發佈:2019-01-25
現象
在做hybrid應用時,我們用WebView來載入html頁面,經常會出現軟體盤彈出,遮擋了html中輸入控制元件(如input)的問題。
無論你是用系統的原生WebView(從4.0-7.0),還是Crosswalk的XWalkView,都有這個問題! (用系統原生瀏覽器是沒有這個問題的)
這裡不得不吐槽一下,ios沒有這個問題。
解決方案有以下幾種:
- 軟鍵盤彈出時WebView高度縮小。
- 軟鍵盤彈出時,WebView內容適當上移。
個人比較喜歡第二個方案,因為:
- 與IOS體驗一致
- 頁面不需要重新佈局,避免了有些頁面在WebView高度縮小後,佈局樣式體驗不好;
1 軟鍵盤彈出時WebView高度縮小(網上大多數也都是說的這個方案)
設定頁面adjustResize
android:windowSoftInputMode="adjustResize"
原理是軟體盤彈出時,整個頁面的大小都縮小了,軟鍵盤不再遮擋WebView了,這個問題自然也就不存在了。
這個方案最簡單。但有時不太好用,如果頁面是上下有固定佈局,中間滾動區域(如上標題欄,下方操作按鈕,中間是可以滾動的資訊輸入區域)。點選中間滾動區域的輸入框,軟鍵盤彈出,會把底部佈局也頂上去,導致中間滾動區域可能高度很小了,顯示效果很差。一
一個辦法是軟鍵盤彈出時,底部佈局隱藏。
window.addEventListener("resize", (v) => {
this .LastWindowHeight = this.CurWindowHeight;
this.CurWindowHeight = window.innerHeight;
if ((this.LastWindowHeight - this.CurWindowHeight) /this.LastWindowHeight > 0.25){
//hide bottom buttons
}else{
//display bottom buttons
}
});
2 軟鍵盤彈出時,WebView內容適當上移
軟鍵盤彈出時,WebView可視區域變小了,可以計算WebView的實際高度,可視高度,將這些資料傳入js,js層根據當前的焦點位置,根據需要上移body。
android:windowSoftInputMode="adjustPan"
public static class HeightVisibleChangeListener implements ViewTreeObserver.OnGlobalLayoutListener {
private WebView webview;
public HeightVisibleChangeListener(WebView webView){
this.webview = webView;
webview.getViewTreeObserver().addOnGlobalLayoutListener(this);
}
int lastHeight;
int lastVisibleHeight;
@Override
public void onGlobalLayout() {
Rect visible = new Rect();
Rect size = new Rect();
webview.getWindowVisibleDisplayFrame(visible);
webview.getHitRect(size);
int height = size.bottom-size.top;
int visibleHeight = visible.bottom - visible.top;
if(height == lastHeight && lastVisibleHeight == visibleHeight) return;
lastHeight = height;
lastVisibleHeight = visibleHeight;
String js = String.format("javascript:heightChange(%1$d , %2$d)",height,visibleHeight);
webview.loadUrl(js);
}
};
初始化webview的時候,初始化一下這個類即可。
new HeightVisibleChangeListener(webView);
上層程式碼,這裡用的是ts
export class KeyboardUtil {
private static height:number;
private static visibleHeight:number;
//android adjustpan 模式下,軟鍵盤遮擋輸入框。
static FixAndroidKeyBoardHideInput(){
window['heightChange'] = (height :number , visibleHeight:number)=>{
KeyboardUtil.OnHeightChange(height,visibleHeight);
}
}
static OnHeightChange(height :number , visibleHeight:number):void{
const body = document.body;
KeyboardUtil.height = body.clientHeight;
KeyboardUtil.visibleHeight = visibleHeight * body.clientHeight /height;
const active = document.activeElement as HTMLElement;
if(height == visibleHeight){
KeyboardUtil.SetElementScrollTop(body , 0);
return;
}
let focusTopRelateWindow = KeyboardUtil.FindElementPositionRelateToWindow(active);
let focusBottomRelateWindow = focusTopRelateWindow + active.clientHeight;
const mindistince = 50;
let bottom = focusBottomRelateWindow + mindistince;
if(bottom > KeyboardUtil.height) bottom = KeyboardUtil.height;
const offset = bottom - KeyboardUtil.visibleHeight;
if(offset <=0){
KeyboardUtil.SetElementScrollTop(body , 0);
return;
}
KeyboardUtil.SetElementScrollTop(body , offset);
}
static SetElementScrollTop(e : HTMLElement , offset : number){
if(offset == 0){
e.style.top = '0';
}else{
e.style.top = '-'+offset +'px';
}
}
static FindElementPositionRelateToWindow(element: HTMLElement) {
let curtop = 0;
let curtopscroll = 0;
if (element.offsetParent) {
do {
curtop += element.offsetTop;
curtopscroll += element.offsetParent ? element.offsetParent.scrollTop : 0;
} while (element = element.offsetParent as HTMLElement);
}
return curtop - curtopscroll;
}
}