How to revoke `requestDisallowInterceptTouchEvent(false)` without lifting finger (Action.UP or Cancel)?

1.4k Views Asked by At

I have WebView(s) inside the RecyclerView. In order to get smooth scrolling experience such that when user scrolls, the RecyclerView will be responsible for scrolling (WebView should not scroll) I called getParent().requestDisallowInterceptTouchEvent(false); inside webview#onTouchEvent(event) when there is only one touch point and is moving vertcially (scrolling up and down).

private void handleSingleFingerTouch(MotionEvent ev) {
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                x1 = ev.getX();
                y1 = ev.getY();
                break;
            case MotionEvent.ACTION_MOVE:
                x2 = ev.getX();
                y2 = ev.getY();
                // -ve param for canScrollHorizontally is to check scroll left. +ve otherwise
                if (Math.abs(x1 - x2) >= Math.abs(y1 - y2)
                        && canScrollHorizontally((int) (x1 - x2))) {
                    // scrolling horizontally. Retain the touch inside the webView.
                    getParent().requestDisallowInterceptTouchEvent(true);
                } else {
                    // scrolling vertically. Share the touch event with the parent.
                    getParent().requestDisallowInterceptTouchEvent(false);
                }
                x1 = x2;
                y1 = y2;
        }
    }

@Override
public boolean onTouchEvent(MotionEvent ev) {
    boolean multiTouch = ev.getPointerCount() > 1;
    if (multiTouch) {
        getParent().requestDisallowInterceptTouchEvent(true);
    } else {
        handleSingleFingerTouch(ev);
    }
    return super.onTouchEvent(ev);
}

It works as expected with just one bug, I found that while RecyclerView(and webview) scrolling and I touch inside the WebView, then RecyclerView stops scrolling as expected, then if I don't lift up my finger but keep finger on the screen and try to zoom, the webview would not zoom and actually it wouldn't receive touch event at all. I have to lift my fingers and touch again to zoom. I know this is because getParent().requestDisallowInterceptTouchEvent(false); won't cancel unless UI receive CANCEL or UP event. I tried to implement an interface that call getParent().requestDisallowInterceptTouchEvent(true); when multi-touch happen. Though it did get called, but seems it doesn't work. Zoom still not happen and onTouchEvent inside the WebView still not get triggered. Any idea to solve this?

1

There are 1 best solutions below

0
On

So basically the solution is to override the onInterceptTouchEvent of the recyclerView

override fun onInterceptTouchEvent(e: MotionEvent): Boolean {
        // When recyclerview is scrolling this will stop scrolling and allow touch event passed to child views.
        if (e.action == MotionEvent.ACTION_DOWN && this.scrollState == RecyclerView.SCROLL_STATE_SETTLING) {
            this.stopScroll()
        }
        return super.onInterceptTouchEvent(e)
    }