在ViewPager中使用WebView

WebView和ViewPager都是我们平时做Android开发非常常用的两个View控件。在一些阅读App和购物App中,我们可能需要在同一个页面上展示多个Tab及WebView。下面我将介绍下,我在ViewPager中使用WebView的一些心得和踩坑总结。

手势滑动

我们知道ViewPager默认支持水平方向手势的滑动翻页效果,根据产品实际的要求,我们可以选择支持手势滑动和屏蔽手势滑动。先说屏蔽的情况,

屏蔽手势滑动的话很简单,上一个StackOverFlow上现成的答案:

How do disable paging by swiping with finger in ViewPager but still be able to swipe programmatically?

如果要支持手势滑动的话,主要会踩到这样一个坑: WebView内部js的水平滑动事件会被屏蔽。也就是说,这里我们遇到了WebView与ViewPager滑动冲突的处理。

首先我们从WebView本身这个View来考虑,我们来看一下WWebView的事件分发方法是否区分当前是否消耗了触摸事件呢?

不幸的是,我们发现,WebView的onTouchEvent(MotionEvent event)方法和dispatchTouchEvent(MotionEvent ev)永远是返回true的,我们可以在google官方的bug反馈平台上看到关于这一点的讨论。

The Android webview.onTouchEvent(event) always return true

官方的回复是这样的:

截图

简单来说就是,WebView上所有的Touch事件都会DOM事件并发送到当前的页面中,但DOM事件的处理呢是异步的,这样就没有办法在同步的onTouch方法中返回事件的处理情况。

也就是说,通过传统的View的事件分发机制来处理js的滑动事件冲突呢,应该是走不通的。

那换个角度,WebView本身是否有一些方法可以获取当前WebView没有消耗的触摸事件呢?

还真让我找到一个方法,void onUnhandledInputEvent(WebView, InputEvent),不过不知道什么原因,这个API21 add的方法,API24的时候被remove了(https://developer.android.com/sdk/api_diff/24/changes/android.webkit.WebViewClient.html)

这里有个stack overflow上的提问,Check if Android WebView is consuming touch events,也基本上和我一个思路,目前也没有好的解决办法。

这么看,只能外部告知java,当前webview是否是可左右滑动的,比如说接口通知,或者js和java的bridge方法入手,这里就不多说了。放个链接,大家自行参考下。

Viewpager与webview滑动冲突的解决方案

不过我偶然发现UC浏览器居然可以处理这个问题!!开启UC浏览器的左滑右滑前进后退功能,在js处理事件的区域,左右滑的手势被屏蔽,在没有处理的区域,左右滑的手势自动启用,还请知道原理的同学不吝告知,多谢!!

WebView资源的释放

直接上代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
* Description: release the memory of web view, otherwise it's resource will not be recycle.
*/
public void clearWebViewResource(ViewGroup container, WebView webView) {
if (webView != null) {
webView.removeAllViews();
// in android 5.1(sdk:21) we should invoke this to avoid memory leak
// see (https://coolpers.github.io/webview/memory/leak/2015/07/16/
// android-5.1-webview-memory-leak.html)
container.removeView(webView);
webView.setTag(null);
webView.clearHistory();
webView.destroy();
}
}