Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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?

like image 251
litaoshen Avatar asked Sep 19 '18 03:09

litaoshen


1 Answers

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)
    }
like image 153
litaoshen Avatar answered Oct 19 '22 00:10

litaoshen