1. 程式人生 > >android軟鍵盤遮擋WebView中input的解決方案

android軟鍵盤遮擋WebView中input的解決方案

現象

在做hybrid應用時,我們用WebView來載入html頁面,經常會出現軟體盤彈出,遮擋了html中輸入控制元件(如input)的問題。
無論你是用系統的原生WebView(從4.0-7.0),還是Crosswalk的XWalkView,都有這個問題! (用系統原生瀏覽器是沒有這個問題的)
這裡不得不吐槽一下,ios沒有這個問題。

解決方案有以下幾種:

  1. 軟鍵盤彈出時WebView高度縮小。
  2. 軟鍵盤彈出時,WebView內容適當上移。

個人比較喜歡第二個方案,因為:

  1. 與IOS體驗一致
  2. 頁面不需要重新佈局,避免了有些頁面在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; 
    }
}