检查Android WebView是否正在使用触摸事件

时间:2015-04-23 11:05:08

标签: android webview

短版

如何检测Android WebView是否消耗了触摸事件? onTouchEvent始终返回true,WebViewClient onUnhandledInputEvent永远不会被触发。

详细版本

我在TwoDScrollView中有多个WebView。顾名思义,TwoDScrollView可以垂直和水平滚动。 TwoDScrollView的内容可以放大/缩小。当用户拖动手指或使用双指缩放时,我想将触摸事件发送到:

  • WebView,如果其内容可滚动/可缩放(即只有WebView内部会滚动/缩放)
  • TwoDScrollView如果上述条件为false(TwoDScrollView的所有内容都将滚动/缩放)

我已使用canScrollHorizontallycanScrollVertically方法部分实现了这一目标。但是这些方法仅适用于原生滚动"。但是,在某些情况下,WebView中的某些JavaScript会消耗触摸事件,例如Google Maps。在这种情况下,方法返回false。有没有办法找出WebView的内容是否消耗触摸事件,即可滚动/可缩放?我无法更改WebView的内容,因此我的问题与this one不同。

我已经考虑通过evaluateJavaScript方法在Webview中执行一些JavaScript来检查触摸处理程序,但是根据this answer,没有简单的方法来实现这一点,而且页面也可以有其他一些嵌套I帧。任何帮助将不胜感激。

我已经尝试了什么

  1. 我覆盖了WebView' onTouchEvent并阅读super.onTouchEvent(),无论如何,它总是返回true。
  2. canScrollHorizontallycanScrollVertically仅部分解决了此问题,如上所述
  3. onScrollChanged不是很有用
  4. WebViewClient.onUnhandledInputEvent永远不会被触发
  5. 我考虑通过evaluateJavaScript使用JavaScript,但这是一个非常复杂和丑陋的解决方案
  6. 我试图通过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,即使有可能在某处发现事件是否被消耗,也需要使用非常丑陋的私有方法。
  7. 注意

    我不需要知道如何拦截发送到WebView的触摸事件,但是WebView是否正在使用它们,即是否正在使用它们执行任何操作,例如滚动,拖动等。

5 个答案:

答案 0 :(得分:1)

根据这个issue report,不可能。 如果Web代码在您的控制之下,您可以实现一些JavaScriptInterface来解决此问题。如果没有,我担心这里没有解决方案。

答案 1 :(得分:0)

您可以通过覆盖touch的{​​{1}}将所有GestureDetector个事件传递给onTouchEvent,这样您就可以知道当Android WebView随时随地都在使用触摸事件时听取WebView

试试这样:

GestureDetector

我希望你受到启发。

答案 2 :(得分:-1)

此代码将处理Webview中的滚动事件。这将捕获点击和点击事件,并比较每个事件的位置。它从不介意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;
    }
}

您还可以尝试控制滑动的速度,将其检测为真正的滑动或滚动。

我希望能帮助你。

答案 3 :(得分:-1)

实际上现在 webview 不支持触​​摸操作。但是有一些解决方法可用; 我将用一个长按示例来展示它:我使用 Pointoption 因为我将获得元素的坐标并将其用于长按。

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.)")));
     
 

答案 4 :(得分:-2)

尝试在XML中设置android:isClickable="true"并在Java代码中创建onClickListener