androidtouch-eventnestedscrollview

NestedScrollView and onInterceptTouchEvent


I do extend NestedScrollView and @Override it's methods: onTouchEvent and onInterceptTouchEvent. The problem is that super.onTouchEvent never calls ACTION_DOWN (it's called by my onIntereceptTouchEvent) and because of that NestedScrollView doesn't move and I get error:

Invalid pointerId=-1 in onTouchEvent

The pointer id is set in onTouchEvent method of NestedScrollView when ACTION_DOWN is triggered.

mActivePointerId = MotionEventCompat.getPointerId(ev, 0);

I cannot set this myself, rewriting whole onTouchEvent methods seems like painful plan. Could use help here. NestedScrollView does move when I click on View which doesn't listen for touch events (basicly that way my onInterecptTouchEvent method is not called and ACTION_DOWN is handled in NestedScrollView onTouchEvent).

@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
    Log.i(LOGTAG, String.valueOf(ev.getAction()));

    final int action = MotionEventCompat.getActionMasked(ev);

    if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {
        mIsBeingDragged = false;
        Log.i(LOGTAG, "is scrolling" + String.valueOf(mIsBeingDragged));
        return false; // Do not intercept touch event, let the child handle it
    }

    switch (action) {
        case MotionEvent.ACTION_DOWN: {
            mStartY = ev.getY();
            break;
        }
        case MotionEvent.ACTION_MOVE: {
            if (mIsBeingDragged) {
                return true;
            }

            final int yDiff = calculateDistanceY(ev);
            Log.d(LOGTAG, "y difference: y");
            if (yDiff > mTouchSlop) {
                mIsBeingDragged = true;
                return true;
            }
            break;
        }
    }
    return false;
}

@Override
public boolean onTouchEvent(MotionEvent ev) {
    Log.i(LOGTAG, "onTouchEvent");
    if (ev.getAction() == MotionEvent.ACTION_CANCEL || ev.getAction() == MotionEvent.ACTION_UP) {
        mIsBeingDragged = false;
    }

    return super.onTouchEvent(ev);
}

Solution

  • Below is the code that fixed my issue, I had to lie:

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        Log.i(LOGTAG, "onTouchEvent");
        if (ev.getAction() == MotionEvent.ACTION_CANCEL || ev.getAction() == MotionEvent.ACTION_UP) {
            mIsBeingDragged = true;
        }
    
        if (mFirstOnTouchEvent) {
            ev.setAction(MotionEvent.ACTION_DOWN);
            ev.setLocation(mStartX, mStartY);
            mFirstOnTouchEvent = false;
        }
    
        return super.onTouchEvent(ev);
    }
    

    And set mFirstOnTouchEvent to true when ACTION_DOWN is triggered in onInterceptTouchEvent:

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
      if (MotionEventCompat.getActionMasked(ev) == MotionEvent.ACTION_DOWN) {
        mFirstOnTouchEvent = true
      }
    
      ...
    }