WebView下拉重新整理與SwipeRefreshLayout事件衝突解決
引言
SwipeRefreshLayout
是Android在 Support.v4
包中為我們提供的使用者重新整理UI的一個元件,大部分場景下我們會使用它包裹 RecyclerView
,在列表上下拖動到頂部時繼續向下滑動檢視觸發重新整理事件,我們可以通過給 SwipeRefreshLayout
設定 OnRefreshListener
通過回撥方法 onRefresh()
來完成下拉重新整理事件的監聽動作。但是當我們把 WebView
作為子View放置在 SwipeRefreshLayout
中時, H5上的scroll
事件與原生安卓的滑動事件就會出現衝突,導致我們無法完成預期的效果,下面看下出現問題的效果圖,然後我們一起解決下這個原生跟H5上的滑動衝突,從而達到我們最終的效果。
問題效果圖

滑動衝突效果圖
從圖上我們可以很清楚的看到,當我們在滑動H5頁的時候,H5頁向下滑動的過程中我們如果向上拖動頁面,會同時觸發先觸發SwipeRefreshLayout上的監聽事件,導致H5頁無法正常向上拖動,但是此時並非我們的預期,我們看下存在滑動衝突事件的程式碼
存在衝突的程式碼
@RequiresApi(api = Build.VERSION_CODES.ECLAIR_MR1) @Override protected void setUpView() { wvPage = findViewById(R.id.wv_page); swipeRefreshLayout = findViewById(R.id.srl_refresh); wvPage.getSettings().setJavaScriptEnabled(true); wvPage.getSettings().setDomStorageEnabled(true); wvPage.setWebViewClient(new WebViewClient()); wvPage.setWebChromeClient(new WebChromeClient()); wvPage.loadUrl(getUrl()); swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { @Override public void onRefresh() { swipeRefreshLayout.setRefreshing(false); wvPage.reload(); } }); ...//省略部分程式碼 }
在上面我們已經提到了出現滑動衝突是由於H5內部的scroll事件與SwipeRefreshLayout滑動監聽發生了衝突,我們只需要找到解決此二者衝突的解決方案,問題就可以迎刃而解。
閱讀SwipeRefreshLayout的原始碼,我們發現這樣一段回撥介面
/** * Classes that wish to override {@link SwipeRefreshLayout#canChildScrollUp()} method * behavior should implement this interface. */ public interface OnChildScrollUpCallback { /** * Callback that will be called when {@link SwipeRefreshLayout#canChildScrollUp()} method * is called to allow the implementer to override its behavior. * * @param parent SwipeRefreshLayout that this callback is overriding. * @param child The child view of SwipeRefreshLayout. * * @return Whether it is possible for the child view of parent layout to scroll up. */ boolean canChildScrollUp(SwipeRefreshLayout parent, @Nullable View child); }
通過這一段程式碼我們瞭解到:OnChildScrollUpCallback 介面就一個canChildScrollUp方法,返回是否可滾動。此時我們可以根據WebView在Y軸方向的滾動距離來判斷當前webview載入的H5頁是否在頂部來決定SwipeRefreshLayout的回撥重新整理方法是否被觸發。
總結如下:
- 當前載入的內容在H5頁頂部時,返回false,表示子檢視不可滾動,refreshLayout接收到滑動事件,引出滑動檢視和呼叫滑動重新整理方法
- 當前載入的內容不在H5頁頂部時,webView.getScrollY() > 0,返回true,表示子檢視可滾動,refreshLayout中canChildScrollUp()返回true,重新整理控制元件不再處理滑動問題,所以沒有呼叫滑動重新整理方法
解決後的效果圖

解決滑動衝突效果圖
程式碼
@RequiresApi(api = Build.VERSION_CODES.ECLAIR_MR1) @Override protected void setUpView() { wvPage = findViewById(R.id.wv_page); swipeRefreshLayout = findViewById(R.id.srl_refresh); wvPage.getSettings().setJavaScriptEnabled(true); wvPage.getSettings().setDomStorageEnabled(true); wvPage.setWebViewClient(new WebViewClient()); wvPage.setWebChromeClient(new WebChromeClient()); wvPage.loadUrl(getUrl()); swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { @Override public void onRefresh() { swipeRefreshLayout.setRefreshing(false); wvPage.reload(); } }); swipeRefreshLayout.setOnChildScrollUpCallback(new SwipeRefreshLayout.OnChildScrollUpCallback() { @Override public boolean canChildScrollUp(@NonNull SwipeRefreshLayout swipeRefreshLayout, @Nullable View view) { return wvPage.getScrollY() > 0;// 原生安卓使用getScrollY()來判斷在Y軸的距離 //return wvPage.getWebScrollY() > 0;// 我專案中使用的X5核心的webview需要呼叫getWebScrollY()來判斷在Y軸的距離 } }); }