html – Android webview: prevent touch gestures being passed to parent viewpager-ThrowExceptions

Exception or error:

I have a viewpager that contains many child views; each child view is a webview. Each webview has some HTML objects that user can interact with; for instance, a slideshow that works on swipe gestures or a draggable circle that user can move around the HTML canvas.

The problem is when user performs a gesture on these HTML objects, the viewpager scrolls to next view. I want the HTML objects to work when user interacts with them (viewpager doesn’t scroll), and the viewpager to scroll when user swipes elsewhere. How can I do that?

Webviews inside Viewpager

P.S. I have used event.preventDefault() and event.stopPropagation() in the JavaScript of the HTML slideshow with hope that the webview would not pass touch events to parent viewpager.

How to solve:

Override the "canScroll" method of your ViewPager and allow scrolling only if the view is not a instance of WebView.

Sample:

public class MyViewPager extends ViewPager {

    public MyViewPager (Context context) {
        super(context);
    }

    public MyViewPager (Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) {
        if(v instanceof WebView){
            return true;
        }
        return super.canScroll(v, checkV, dx, x, y);
    }

}

###

Create your own subclass of ViewPager and overwrite canScroll as follows.

class MyViewPager extends ViewPager {
...

@Override
protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) {
    if (isInsideSlideShow(x,y)) {
        return true; // allow the slide show its own scrolling
    } else {
        return false; // ViewPager scrolls
    }
}

You will somehow of course need to know, which part of the screen is covered by the slide show.
This knowledge must be implemented in the method isInsideSlideShow.

If you can’t get hold of the x/y coordinates of the slide show, another solution could be to use gestures starting at the very border of the view as paging gestures and gestures starting more in the inner area as slide show gestures.

I am using this approach for a view pager which shows a map and a graph. Both are supporting their own panning. But when the user starts the gesture at the left or right border, the whole map or graph is slid away:

@Override
protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) {
        int width = getWidth();
        int slideWidth = Math.round(width * 0.15f);
        if (x < slideWidth || x > width - slideWidth) {
            return false;
        }
        return true;
}

###

My idea was to implement a Javascript function that decides which parts to scroll:

function checkScroll(x, y){
    var o = document.elementFromPoint(x, y);
    result = $('div.swiper-container').find(o).length;
    MyAndroidInterface.processReturnValue(result);
}

Then override these two methods:

@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
    @Override
public boolean onTouchEvent(MotionEvent ev) {
    switch (ev.getAction()) {
    case MotionEvent.ACTION_DOWN:
        homepage.callJavascript("checkScroll(" + Math.round(ev.getX()) + "," + Math.round(ev.getY()) + ")");
        return super.onTouchEvent(ev);
    case MotionEvent.ACTION_MOVE:
        if (homepage.scrollSlideshowLock())
            return false;

Leave a Reply

Your email address will not be published. Required fields are marked *