Implementing pinch-zoom and pan/drag in an Android view on the canvas

by vivin

As I had mentioned before, we are able to pan and zoom but we still have problems: panning continues in all directions indefinitely, and our canvas “jerks” when we pan, lift our finger, and then pan again; it doesn’t remember where we left off. Let’s start with the second problem first, as it’s the easier one. The reason that our canvas jerks is precisely because we don’t keep track of where we left off, the last time we panned. This is fine if you’re translating just once from the origin. However, if you want to translate again, you need to remember how much you’ve already translated by, otherwise the canvas is going to jerk back to where you place your finger again. To fix this problem, we use two new variables: previousTranslateX and previousTranslateY:

public class ZoomView extends View {

    ...
    ...

    //These two variables keep track of the amount we translated the X and Y coordinates, the last time we
    //panned.
    private float previousTranslateX = 0f;
    private float previousTranslateY = 0f;

    ...
    ...

    @Override
    public boolean onTouchEvent(MotionEvent event) {

        switch (event.getAction() & MotionEvent.ACTION_MASK) {
            case MotionEvent.ACTION_DOWN:
                mode = DRAG;

                //We assign the current X and Y coordinate of the finger to startX and startY minus the previously translated
                //amount for each coordinates This works even when we are translating the first time because the initial
                //values for these two variables is zero.               
                startX = event.getX() - previousTranslateX;
                startY = event.getY() - previousTranslateY;
                break;

            case MotionEvent.ACTION_MOVE:
                //We calculate the values of translateX and translateY by finding the difference between the X/Y coordinate
                //and the starting X/Y coordinate. Since this event is fired every time the finger moves, we're constantly
                //updating the values of these two coordinates
                translateX = event.getX() - startX;
                translateY = event.getY() - startY;
                break;

            case MotionEvent.ACTION_POINTER_DOWN:
                mode = ZOOM;
                break;

            case MotionEvent.ACTION_UP:
                mode = NONE;

                //All fingers went up, so let's save the value of translateX and translateY into previousTranslateX and 
                //previousTranslateY
                previousTranslateX = translateX;
                previousTranslateY = translateY;
                break;

            case MotionEvent.ACTION_POINTER_UP:
                mode = DRAG;
                //This is not strictly necessary; we save the value of translateX and translateY into previousTranslateX
                //and previousTranslateY when the second finger goes up
                previousTranslateX = translateX;
                previousTranslateY = translateY;
                break;       
        }

        ...
        ...
    }
}