Search code examples
androidtouch-eventdouble-clickpanning

How to make double tap and panning work at same time, in Android?


So I'm trying to get my view working with many different ways, there should be:

  • Multitouch for zooming
  • Touchlistener for panning
  • Doubleclick for restoring zoom
  • or if it's already restored it will zoom the place where double click was.

At the moment, everything else is working but when I doubleclick and keep second click down and continue moving it the code is working that way it first restores/zooms and then panning starts.

So because of zoomscale, it will sometimes first change the size of canvas and then start panning. What should I do to enable panning after double click noticed? Or something like check if double click's last click keeps moving and skip the zoom/restore thing? My code looks like this atm. And I am trying to return false after doubleclick but it doesnt really effect... Would there be something like setting ignoreMultiTouch to true, but on double click or panning?

@Override
public boolean onTouchEvent(MotionEvent ev) {
    if(mgestureDetector.onTouchEvent(ev)){
        mOnTouchEventWorkingArray[0] = ev.getX();
        mOnTouchEventWorkingArray[1] = ev.getY();

        mOnTouchEventWorkingArray = scaledPointsToScreenPoints(mOnTouchEventWorkingArray);

        ev.setLocation(mOnTouchEventWorkingArray[0], mOnTouchEventWorkingArray[1]);
        mScaleDetector.onTouchEvent(ev);

        final int action = ev.getAction();
        switch (action & MotionEvent.ACTION_MASK) {
            case MotionEvent.ACTION_DOWN: {
                final float x = ev.getX();
                final float y = ev.getY();

                mLastTouchX = x;
                mLastTouchY = y;

                // Save the ID of this pointer
                mActivePointerId = ev.getPointerId(0);
                break;
            }

            case MotionEvent.ACTION_MOVE: {
                // Find the index of the active pointer and fetch its position
                final int pointerIndex = ev.findPointerIndex(mActivePointerId);
                final float x = ev.getX(pointerIndex);
                final float y = ev.getY(pointerIndex);

                final float dx = x - mLastTouchX;
                final float dy = y - mLastTouchY;


                mPosX += dx;
                mPosY += dy;
                mTranslateMatrix.preTranslate(dx, dy);
                mTranslateMatrix.invert(mTranslateMatrixInverse);

                mLastTouchX = x;
                mLastTouchY = y;
                normal = false;

                invalidate();
                break;
            }

            case MotionEvent.ACTION_UP: {
                mActivePointerId = INVALID_POINTER_ID;
                break;
            }

            case MotionEvent.ACTION_CANCEL: {
                mActivePointerId = INVALID_POINTER_ID;
                break;
            }

            case MotionEvent.ACTION_POINTER_UP: {
                // Extract the index of the pointer that left the touch sensor
                final int pointerIndex = (action & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
                final int pointerId = ev.getPointerId(pointerIndex);
                if (pointerId == mActivePointerId) {
                    // This was our active pointer going up. Choose a new
                    // active pointer and adjust accordingly.
                    final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
                    mLastTouchX = ev.getX(newPointerIndex);
                    mLastTouchY = ev.getY(newPointerIndex);
                    mActivePointerId = ev.getPointerId(newPointerIndex);
                }
                break;

            }
        }
    }
    return true;

}

private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {

    @Override
    public boolean onScale(ScaleGestureDetector detector) {
        mScaleFactor *= detector.getScaleFactor();
        if (detector.isInProgress()) {
            mFocusX = detector.getFocusX();
            mFocusY = detector.getFocusY();
        }
        mScaleFactor = Math.max(0.75f, Math.min(mScaleFactor, 3.0f));
        mScaleMatrix.setScale(mScaleFactor, mScaleFactor,
                mFocusX, mFocusY);
        mScaleMatrix.invert(mScaleMatrixInverse);
        invalidate();
        requestLayout();

        return true;
    }
}

private class GestureListener extends GestureDetector.SimpleOnGestureListener {

    @Override
    public boolean onDown(MotionEvent e) {
        return true;
    }

    // event when double tap occurs
    @Override
    public boolean onDoubleTap(MotionEvent e) {
        if (!normal) {
            restore();
        } else {
            zoomToSpot(e);
        }
        return false;
    }


    @Override
    public boolean onDoubleTapEvent(MotionEvent e) {
        return true;
    }
}

Solution

  • So I made my code working with these little things, first I added the doubleclicked boolean

    public boolean onDoubleTap(MotionEvent e) {
            if (!normal) {
                restore();
            } else {
                zoomToSpot(e);
            }
            doubleclicked = true;
            return true;
        }
    

    then I made two different onTouchEvents and set the first only working if doubleclicked is false. The second one will set doubleclicked false when there is no fingers left on screen.

    public boolean onTouchEvent(MotionEvent ev) {
    
        final int action = ev.getAction();
    
        if (!doubleclicked) {
            switch (action & MotionEvent.ACTION_MASK) {
                case MotionEvent.ACTION_DOWN: {
                    //something...
            }
        } else {
            switch (action & MotionEvent.ACTION_MASK) {
                case MotionEvent.ACTION_UP: {
                    doubleclicked = false;
                    break;
                }
             }
         }