SwipeRefreshLayout與WebView內部子可滾動div衝突

weixin_33935777發表於2018-12-27

問題參見下圖(圖片來自於網路:))


14125002-3b6344b32504e42d.gif
20170901174631281.gif

下圖是我的頁面,分為3個div,三個div的高度加起來是100%佔據整個webview頁面。而最下面的第三個div是一個可滾動的div(overflow: "auto")。往上滑動時沒問題的,但是往下滑動就會出現上面gif中的問題。


14125002-8f39fdf3b3963feb.png
image.png

網上有如下解決方案,但是針對這個案例是無效的,因為本案例中webView.getScrollY始終為0(三個div構成了整個webview頁面,自始至終這三個div位置是不會變化的,是固定的)
// 設定子檢視是否允許滾動到頂部
    refreshLayout.setOnChildScrollUpCallback(new SwipeRefreshLayout.OnChildScrollUpCallback() {
       @Override
       public boolean canChildScrollUp(SwipeRefreshLayout parent, @Nullable View child) {
           return webView.getScrollY() > 0;
       }
    });

所以問題在於如何監聽webview頁面內子佈局的滾動,以子佈局的滾動來控制重新整理動作。
可以利用webview的evaluateJavascript方法來監聽特定元素,第一個引數script用於執行一段js指令碼以獲取指定元素的指定屬性比如div的height,第二個引數resultCallback是一個回撥函式,當取到第一個引數指定的屬性時就會執行呼叫。

public void evaluateJavascript(String script, ValueCallback<String> resultCallback)

所以解決方案很明瞭了。只需要利用evaluateJavascript來監聽可滾動的div的scrollTop值,當其為0時表示在頂端,此時下拉可以重新整理。否則禁止下拉重新整理。注意,這裡需要和前端商量約定統一的要監聽的元素的id,即下面的inner_scroll_box。

webView.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View view, MotionEvent motionEvent) {
                switch (motionEvent.getAction()) {

                    case MotionEvent.ACTION_MOVE:
                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
                            webView.evaluateJavascript("document.getElementById(\"inner_scroll_box\").scrollTop", new ValueCallback<String>() {
                                @Override
                                public void onReceiveValue(String value) {
                                    if (!TextUtils.isEmpty(value) && !"null".equals(value)) {
                                        if (Integer.parseInt(value) == 0) {
                                            refreshLayout.setEnabled(true);
                                        } else {
                                            refreshLayout.setEnabled(false);
                                        }
                                    }
                                }
                            });
                         }
                         break;
              }
}

對於沒有id的React元件,比如antd mobile元件Picker,就需要新增一個隱藏的div,然後根據Picker的狀態的改變來改變div的height,最後就可以在android端根據div的高度來決定是否可以下拉重新整理了。


14125002-7567d126f59e16c3.png
Picker

新增id為type_picker的隱藏div,在onVisibleChange中根據Picker列表的隱藏狀態來改變div的高度。

<div>
                <Picker data={vms} cols={1} title={"資金型別"} value={this.state.value} extra={v2label[this.state.value]}
                    onChange={v => {if (v === this.state.value) {this.handleChange(v2type[v]);this.setState({ value: v })}}}
                    onVisibleChange={v => {if (v===true) {document.getElementById('type_picker').style.height="1px"} else {document.getElementById('type_picker').style.height="0px"}}}
                >
                    <CustomPickerButton/>
                </Picker>
                {/*新增此div是為了與android端進行特殊操作,讓android端知道Picker隱藏狀態*/}
                <div id={"type_picker"} style={{visibility: "none", height: 0}}></div>
            </div>

在android端根據id為type_picker的div的高度來決定是否可以下拉重新整理。

webView.evaluateJavascript("document.getElementById(\"type_picker\").style.height", new ValueCallback<String>() {
                                @Override
                                public void onReceiveValue(String value) {
                                    if (!TextUtils.isEmpty(value) && !"null".equals(value)) {
                                        if (!"0px".equals(value.replace("\"", ""))) {
                                            refreshLayout.setEnabled(false);
                                        } else {
                                            refreshLayout.setEnabled(true);
                                        }
                                    }
                                }
                            });

相關文章