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

by vivin

Now that we’ve identified the different states we are in, we can go on and start to implement the dragging/panning functionality. Panning essentially equates to a translation operation on the canvas. By translating the canvas, we control what part of the zoomed-in canvas we display on the device screen. So what information do we need to translate? Well, think about what we expect to see when we pan. We place our finger on the screen and then we move it by a certain amount in a certain direction. We essentially expect the image to move by that same amount, in that same direction as well. So the direction and magnitude that we need to translate the image by, can be gathered from the coordinate where we first pressed the screen, through each point until we take our finger off the screen. Getting all this information is pretty easy. We can get the X and Y coordinate of the finger using event.getX() and event.getY(). So all we need to do is get the X and Y coordinate when we first press our finger on the screen, and translate the image as we move our finger across the screen, by getting the finger’s X and Y coordinates each time the finger moves. We can do that like this:

public class ZoomView extends View {

    ...
    ...

    //These two variables keep track of the X and Y coordinate of the finger when it first
    //touches the screen
    private float startX = 0f;
    private float startY = 0f;

    //These two variables keep track of the amount we need to translate the canvas along the X
    //and the Y coordinate
    private float translateX = 0f;
    private float translateY = 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. So these variables now
                //hold the X and Y coordinate of the finger as it first touches the screen.                
                startX = event.getX();
                startY = event.getY();
                ...
                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;
       
            ...
            ...
        }

        ...
        ...
    }
}