检查 Android WebView 是不是正在使用触摸事件
Posted
技术标签:
【中文标题】检查 Android WebView 是不是正在使用触摸事件【英文标题】:Check if Android WebView is consuming touch events检查 Android WebView 是否正在使用触摸事件 【发布时间】:2015-07-01 12:39:49 【问题描述】:TL;DR
如何检测 android WebView 是否使用了触摸事件? onTouchEvent
始终返回 true,并且永远不会触发 WebViewClient
的 onUnhandledInputEvent
。
详细说明
我在 TwoDScrollView 中有多个 WebView。顾名思义,TwoDScrollView 可以垂直和水平滚动。 TwoDScrollView 的内容可以放大/缩小。当用户拖动手指或使用捏合缩放时,我想将触摸事件发送到:
WebView 如果其内容是可滚动/可缩放的(即只有 WebView 内部会滚动/缩放) TwoDScrollView 如果上述条件为假(TwoDScrollView 的所有内容都会滚动/缩放)我已经通过使用canScrollHorizontally
和canScrollVertically
方法部分实现了这一点。但这些方法仅适用于“本机滚动”。但是,在某些情况下,WebView 中的某些 javascript 会使用触摸事件,例如 Google Maps。在这种情况下,这些方法返回 false。有没有办法找出 WebView 的内容是否消耗触摸事件,即是否可滚动/可缩放?我无法更改 WebView 的内容,因此我的问题与 this one 不同。
我考虑过通过evaluateJavaScript
方法在Webview 中执行一些JavaScript 来检查触摸处理程序,但是根据this answer 没有简单的方法来实现这一点,而且页面可以有一些其他嵌套的iframe。任何帮助将不胜感激。
我已经尝试过的
-
我覆盖了 WebView 的
onTouchEvent
并读取了 super.onTouchEvent()
,无论如何它总是返回 true。
canScrollHorizontally
和 canScrollVertically
只是部分解决了这个问题,如上所述
onScrollChanged
也没用
WebViewClient.onUnhandledInputEvent
永远不会被触发
我曾考虑通过evaluateJavaScript
使用JavaScript,但这是一个非常复杂且丑陋的解决方案
我试图通过Debug.startMethodTracing
跟踪 MotionEvent。我发现它的传播方式如下:
android.webkit.WebView.onTouchEvent
com.android.webview.chromium.WebViewChromium.onTouchEvent
com.android.org.chromium.android_webview.AwContents.onTouchEvent
com.android.org.chromium.android_webview.AwContents$AwViewMethodsImpl.onTouchEvent
com.android.org.chromium.content.browser.ContentViewCore.onTouchEventImpl
根据ContentViewCore's source code,触摸事件以原生方法nativeOnTouchEvent
结束,我不知道接下来会发生什么。无论如何,onTouchEvent
总是返回 true,即使可以在某个地方找出事件是否被消费,也需要使用私有方法,这也很丑陋。
注意
我不需要知道如何拦截发送到 WebView 的触摸事件,但 WebView 是否正在使用它们,即是否正在使用它们来做任何事情,例如滚动、拖动等。
【问题讨论】:
您是否尝试查看此链接***.com/questions/12578895/…。 等等我不清楚。你试过只打电话 webview.setOnTouchListener 吗? @Smashing:我知道如何拦截触摸事件到WebView,但我需要知道WebView是否消耗了它们。例如,如果用户正在拖动手指并且 WebView 中的某些内容正在使用它(例如地图正在滚动),我需要获取“true”。否则,如果 WebView 中没有任何内容使用触摸(没有可滚动内容等),我需要获取“false”,以便我可以将触摸事件用于我自己的用途。 @dabluck setOnTouchListener 允许我将触摸事件发送到 WebView,但没有告诉我 WebView 是否消耗了这些事件。 铬问题跟踪器上有一个类似的问题:code.google.com/p/chromium/issues/detail?id=515799 【参考方案1】:实际上现在 webview 不支持 Touch Actions。但是有一些解决方法可用; 我将通过一个 longpress 示例来展示它:我正在使用 Pointoption,因为我将获取元素的坐标并将其用于 longpress。
public void longpress(PointOption po)
//first you need to switch to native view
driver.switchToNativeView();
TouchAction action = new TouchAction((PerformsTouchActions) driver);
action.longPress(po).waitAction(WaitOptions.waitOptions(Duration.ofSeconds(2)));
action.release();
action.perform();
driver.switchToDefaultWebView();
为了得到我在methood下设计的元素的坐标
public PointOption getElementLocation(WebElement element)
int elementLocationX;
int elementLocationY;
//get element location in webview
elementLocationX = element.getLocation().getX();
elementLocationY = element.getLocation().getY();
//get the center location of the element
int elementWidthCenter = element.getSize().getWidth() / 2;
int elementHeightCenter = element.getSize().getHeight() / 2;
int elementWidthCenterLocation = elementWidthCenter + elementLocationX;
int elementHeightCenterLocation = elementHeightCenter + elementLocationY;
//calculate the ratio between actual screen dimensions and webview dimensions
float ratioWidth = device.getDeviceScreenWidth() / ((MobileDevice) device)
.getWebViewWidth().intValue();
float ratioHeight = device.getDeviceScreenHeight() / ((MobileDevice) device)
.getWebViewHeight().intValue();
//calculate the actual element location on the screen , if needed you can increase this value,for example i used 115 for one of my mobile devices.
int offset = 0;
float elementCenterActualX = elementWidthCenterLocation * ratioWidth;
float elementCenterActualY = (elementHeightCenterLocation * ratioHeight) + offset;
float[] elementLocation = elementCenterActualX, elementCenterActualY;
int elementCoordinateX, elementCoordinateY;
elementCoordinateX = (int) Math.round(elementCenterActualX);
elementCoordinateY = (int) Math.round(elementCenterActualY);
PointOption po = PointOption.point(elementCoordinateX, elementCoordinateY);
return po;
现在您有一个 longpress(PointOption po) 和 getElementLocation(Webelement element) 方法可以为您提供 po。现在一切准备就绪,您可以按如下方式使用它们..
longpress(getElementLocation(driver.findElement(By.id("the selector can be any of them(xpath,css,classname,id etc.)")));
【讨论】:
【参考方案2】:根据这个issue report,不可能。 如果 web 代码在你的控制之下,你可以实现一些 JavaScriptInterface 来解决这个问题。如果不是,恐怕这里没有办法。
【讨论】:
【参考方案3】:尝试在 XML 中设置 android:isClickable="true"
,并在 Java 代码中创建 onClickListener
。
【讨论】:
【参考方案4】:此代码将处理您在 web 视图中的滚动事件。这会捕获单击向下和单击向上事件,并比较每个事件的位置。没关系 webview 内的内容是可滚动的,只要比较 webview 区域内的坐标即可。
public class MainActivity extends Activity implements View.OnTouchListener, Handler.Callback
private float x1,x2,y1,y2; //x1, y1 is the start of the event, x2, y2 is the end.
static final int MIN_DISTANCE = 150; //min distance for a scroll event
private static final int CLICK_ON_WEBVIEW = 1;
private static final int CLICK_ON_URL = 2;
private static final int UP_ON_WEBVIEW = 3;
private final Handler handler = new Handler(this);
public WebView webView;
private WebViewClient client;
private WebAppInterface webAppInt = new WebAppInterface(this);
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
webView = (WebView)findViewById(R.id.myWebView);
webView.setOnTouchListener(this);
client = new WebViewClient();
webView.setWebViewClient(client);
webView.loadDataWithBaseURL("file:///android_asset/", "myweb.html", "text/html", "UTF-8", "");
//HERE START THE IMPORTANT PART
@Override
public boolean onTouch(View v, MotionEvent event)
if (v.getId() == R.id.myWebView && event.getAction() == MotionEvent.ACTION_DOWN)
x1 = event.getX();
y1 = event.getY();
handler.sendEmptyMessageDelayed(CLICK_ON_WEBVIEW, 200);
else if (v.getId() == R.id.myWebView && event.getAction() == MotionEvent.ACTION_UP)
x2 = event.getX();
y2 = event.getY();
handler.sendEmptyMessageDelayed(UP_ON_WEBVIEW, 200);
return false;
@Override
public boolean handleMessage(Message msg)
if (msg.what == CLICK_ON_URL) //if you clic a link in the webview, thats not a scroll
handler.removeMessages(CLICK_ON_WEBVIEW);
handler.removeMessages(UP_ON_WEBVIEW);
return true;
if (msg.what == CLICK_ON_WEBVIEW)
//Handle the click in the webview
Toast.makeText(this, "WebView clicked", Toast.LENGTH_SHORT).show();
return true;
if (msg.what == UP_ON_WEBVIEW)
float deltaX = x2 - x1; //horizontal move distance
float deltaY = y2 - y1; //vertical move distance
if ((Math.abs(deltaX) > MIN_DISTANCE) && (Math.abs(deltaX) > Math.abs(deltaY)))
// Left to Right swipe action
if (x2 > x1)
//Handle the left to right swipe
Toast.makeText(this, "Left to Right swipe", Toast.LENGTH_SHORT).show ();
// Right to left swipe action
else
//Handle the right to left swipe
Toast.makeText(this, "Right to Left swipe", Toast.LENGTH_SHORT).show ();
else if ((Math.abs(deltaY) > MIN_DISTANCE) && (Math.abs(deltaY) > Math.abs(deltaX)))
// Top to Bottom swipe action
if (y2 > y1)
//Handle the top to bottom swipe
Toast.makeText(this, "Top to Bottom swipe", Toast.LENGTH_SHORT).show ();
// Bottom to top swipe action -- I HIDE MY ACTIONBAR ON SCROLLUP
else
getActionBar().hide();
Toast.makeText(this, "Bottom to Top swipe [Hide Bar]", Toast.LENGTH_SHORT).show ();
return true;
return false;
您还可以尝试控制滑动速度,将其检测为真正的滑动或滚动。
希望对你有帮助。
【讨论】:
【参考方案5】:您可以通过覆盖WebView
中的onTouchEvent
将所有touch
事件传递给GestureDetector
,这样您就可以随时随地通过收听@了解Android WebView 何时消费触摸事件 987654325@.
试试这样:
public class MyWebView extends WebView
private Context context;
private GestureDetector gestDetector;
public MyWebView(Context context)
super(context);
this.context = context;
gestDetector = new GestureDetector(context, gestListener);
@Override
public boolean onTouchEvent(MotionEvent event)
return gd.onTouchEvent(event);
GestureDetector.SimpleOnGestureListener gestListener= new GestureDetector.SimpleOnGestureListener()
public boolean onDown(MotionEvent event)
return true;
public boolean onFling(MotionEvent event1, MotionEvent event2, float velocityX, float velocityY)
//if (event1.getRawX() > event2.getRawX())
// show_toast("swipe left");
// else
// show_toast("swipe right");
//
//you can trace any touch events here
return true;
;
void show_toast(final String text)
Toast t = Toast.makeText(context, text, Toast.LENGTH_SHORT);
t.show();
希望你受到启发。
【讨论】:
我了解 GestureDetector 帮助我将原始系列 MotionEvents 转换为一些手势,例如轻击、滚动双击等,但它并没有解决我的问题,即确定 WebView 是否使用了触摸事件一些内部处理。以上是关于检查 Android WebView 是不是正在使用触摸事件的主要内容,如果未能解决你的问题,请参考以下文章
Android - 检查元素是不是存在于 WebView 中(在 DOM 中)