Multi Touch in Android – Translate, Scale, and Rotate

Here’s a quick and easy implementation of Android’s multi touch feature – one finger to move, two to zoom, and three to rotate the image.

Assuming you have a basic understanding of 2D matrix transformations, the Matrix class in Android uses a 3×3 matrix to achieve all of the 2D transformations.

The source code and pre -built APK is available. See the end of this post.

Main activity –

package com.multitouch.example;

import android.os.Bundle;
import android.util.FloatMath;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.ImageView;

public class MultiTouch extends Activity implements OnTouchListener {

    // these matrices will be used to move and zoom image
    private Matrix matrix = new Matrix();
    private Matrix savedMatrix = new Matrix();
    // we can be in one of these 3 states
    private static final int NONE = 0;
    private static final int DRAG = 1;
    private static final int ZOOM = 2;
    private int mode = NONE;
    // remember some things for zooming
    private PointF start = new PointF();
    private PointF mid = new PointF();
    private float oldDist = 1f;
    private float d = 0f;
    private float newRot = 0f;
    private float[] lastEvent = null;

    public void onCreate(Bundle savedInstanceState) {
        ImageView view = (ImageView) findViewById(;

    public boolean onTouch(View v, MotionEvent event) {
        // handle touch events here
        ImageView view = (ImageView) v;
        switch (event.getAction() & MotionEvent.ACTION_MASK) {
            case MotionEvent.ACTION_DOWN:
                start.set(event.getX(), event.getY());
                mode = DRAG;
                lastEvent = null;
            case MotionEvent.ACTION_POINTER_DOWN:
                oldDist = spacing(event);
                if (oldDist > 10f) {
                    midPoint(mid, event);
                    mode = ZOOM;
                lastEvent = new float[4];
                lastEvent[0] = event.getX(0);
                lastEvent[1] = event.getX(1);
                lastEvent[2] = event.getY(0);
                lastEvent[3] = event.getY(1);
                d = rotation(event);
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_POINTER_UP:
                mode = NONE;
                lastEvent = null;
            case MotionEvent.ACTION_MOVE:
                if (mode == DRAG) {
                    float dx = event.getX() - start.x;
                    float dy = event.getY() - start.y;
                    matrix.postTranslate(dx, dy);
                } else if (mode == ZOOM) {
                    float newDist = spacing(event);
                    if (newDist > 10f) {
                        float scale = (newDist / oldDist);
                        matrix.postScale(scale, scale, mid.x, mid.y);
                    if (lastEvent != null && event.getPointerCount() == 3) {
                        newRot = rotation(event);
                        float r = newRot - d;
                        float[] values = new float[9];
                        float tx = values[2];
                        float ty = values[5];
                        float sx = values[0];
                        float xc = (view.getWidth() / 2) * sx;
                        float yc = (view.getHeight() / 2) * sx;
                        matrix.postRotate(r, tx + xc, ty + yc);

        return true;

     * Determine the space between the first two fingers
    private float spacing(MotionEvent event) {
        float x = event.getX(0) - event.getX(1);
        float y = event.getY(0) - event.getY(1);
        return FloatMath.sqrt(x * x + y * y);

     * Calculate the mid point of the first two fingers
    private void midPoint(PointF point, MotionEvent event) {
        float x = event.getX(0) + event.getX(1);
        float y = event.getY(0) + event.getY(1);
        point.set(x / 2, y / 2);

     * Calculate the degree to be rotated by.
     * @param event
     * @return Degrees
    private float rotation(MotionEvent event) {
        double delta_x = (event.getX(0) - event.getX(1));
        double delta_y = (event.getY(0) - event.getY(1));
        double radians = Math.atan2(delta_y, delta_x);
        return (float) Math.toDegrees(radians);

An important function that is always used is postXx(). This function concats a new matrix of the type Xx to the existing matrix object. Using setXx() will reset the matrix’s Xx property.
Main layout – main.xml

<?xml version="1.0" encoding="utf-8"?>


<ImageView android:id="@+id/imageView"
android:scaleType="matrix" />


Browse and download the source code on GitHub.


  1. Zurab

    This code make the image itself act within the ImageView boarders, but is it possible to make ImageView act? in addition if I add several views on the view group the last one is active and covers previous ones… any suggestions?

    • Yes, it is possible. I have done so with another app.
      To bring the touched view to front, use bringToFront() on the view

        • Well, everything is pretty much the same. The main difference is that instead of view.setImageMatrix(matrix); on line 110(refer to your pastebin link), calculate the X and Y coordinates from the matrix, along with the scale factor and rotation, and use it directly on the view. A view has setX(), setY(), setScaleX(), setScaleY(), and setRotation(). More on these methods here:

          • Reeya

            i have used if (mode == DRAG) { view.setX(dx), view.setY(dy)} for drag function i can able to multiple images but drag is working not smooth

          • Reeya

            zooming is flickering view.setScaleX(x), view.setScaleY(y). how to make the zooming is smooth

            • Zurab

              unfortunately I failed to apply those settings to the view itself :(

              • Reeya

                just i copied the above code and tried like this view.setScaleX and view.setScaleY. please if you find the solution help me how to scale and rotate smoothly.

                CODE BLOCK DELETED. Please paste code at

                • Zurab

                  ok, here is my code, I have two classes, first is the custom imageView using the above code:
                  and main class, where I declare this custom class… and here is where I use it:
                  however, the problem is, that when I set newChild dimensions as fill_parent, each new child overlaps the previous one… and it I don’t set the dimens, the image is rotated/zoomed/moved withing the imageview bounds, so the action is performed on the matrix not the view itself :( I’m not that strong in coding, so if you find any solution, maybe you also could post it here :)))

  2. Zurab

    thnx to the author, it took me significant time to find this page :)))) and it saved a lot more :)

  3. Kirill

    Hey, I’m just interested – why didn’t you use GestureScaleDetector for this purpose? Is there any problem with GestureScaleDetector? Maybe I misunderstand but isn’t this detector serves the same purpose?


    • Reeya

      This example code is working perfectly as my need only addition thing i need to apply for multiple image view to drag , re-size and rotate. pls provide me some peace of code to add multiple images to drag, drop and scale

      • Vicky

        You can Create a custom “ImageView” Class using the above code to perform scaling, rotation and moving. And then Insert the objects of that class in your “MainActivity” in FrameLayout or any ViewGroup. and as suggested by Jude, you can then Activate the specific ImageView by detecting the touch area.
        If you want any other help regarding the multiple Images. You can contact me at, if Jude don’t mind. ;)

        • Reeya

          I have created Custome ImageView and added multiple images dynamically.

          Issues: 1.The images is smaller that the image view.
          2. I can able to move , scale and rotate the images with in the image view.

          I need to move scale and rotate the images in the whole layout. how to do that. I have attached my code pls help me.

          Activity Class:
          public class ImageViewDrag extends Activity {

          private static final String TAG = “Touch”;

          LinearLayout selectedLayout ;

          int [] images = {R.drawable.r1 , R.drawable.r10};

          public void onCreate(Bundle savedInstanceState) {

          selectedLayout = (LinearLayout)findViewById(;
          View view = new View(this);
          for(int i =0; i <2 ;i ++)

          DraggableView imageView = new DraggableView(this);

          LinearLayout.LayoutParams vp = new LinearLayout.LayoutParams(400, 400);

          else if(i==1)





          Custom Image View:

          public class DraggableView extends ImageView implements OnTouchListener {

          Matrix matrix = new Matrix();
          Matrix savedMatrix = new Matrix();
          PointF start = new PointF();
          PointF mid = new PointF();
          float oldDist = 1f;
          public DraggableView(Context context) {

          public boolean onTouch(View v, MotionEvent event) {
          ImageView view = (ImageView) v;
          LinearLayout.LayoutParams vp = new LinearLayout.LayoutParams(200,200);

          switch (event.getAction() & MotionEvent.ACTION_MASK) {
          case MotionEvent.ACTION_DOWN:
          start.set(event.getX(), event.getY());
          case MotionEvent.ACTION_UP:

          case MotionEvent.ACTION_MOVE:
          matrix.postTranslate(event.getX() – start.x, event.getY()
          – start.y);



          return true;


  4. Reeya

    how to add multiple images in your code please explain it. i am new to android

    • You’ll have to create and maintain a map for multiple images. Then find out which one was touched and make that the active one for operations.

  5. vicky

    Thanx for the code. I implemented the code but the rotation is not working. The device supports multi touch. Can you tell me how to set the rotation to work with 2 fingers.

  6. Kirill

    Could you please clarify, what is the purpose for ‘lastEvent’ array in the code? I don’t see when we its values…

  7. kibzorg

    nice work, but while in rotation image goes out of the view , so how can i set rotation without changing its position in matrix.using 2 finger. answer urgently required.

    • Please refer to my other article, titled “Calculate the REAL scale factor and the angle of rotation from an Android Matrix”.

  8. Makati

    Hi, I want to clarify what if I have 2 or more small images that I want to resize. How do I do? I tried your work but the imageview container does not change the width and height.

    • Maintain a mapping between an imageview and it’s associated matrix. Then, when a pointer down event type occurs, figure out which imageview was touched, and set that as the active one to perform operations on.

  9. erick

    Thank you Jude for a working example. but I’m having a tough time implementing it on multiple imageviews. the fill_parent wont allow me to touch the imageview behind. hope you can help..

  10. Pingback: ImageView onTouchListener: cant touch the imageview behindCopyQuery CopyQuery | Question & Answer Tool for your Technical Queries,CopyQuery, ejjuit, query, copyquery,, android doubt, ios question, sql query, sqlite query, nodejsquery, dn

  11. Pingback: resizing imageView container after scaling image (matrix)CopyQuery CopyQuery | Question & Answer Tool for your Technical Queries,CopyQuery, ejjuit, query, copyquery,, android doubt, ios question, sql query, sqlite query, nodejsquery, dns

  12. Pingback: scale imageView on relative layoutCopyQuery CopyQuery | Question & Answer Tool for your Technical Queries,CopyQuery, ejjuit, query, copyquery,, android doubt, ios question, sql query, sqlite query, nodejsquery, dns query, update query, i

  13. Manoj

    Hi, your code works fine. But I need to do the same for multiple images also, In my case I have two images say Image-A and Image-B, It works fine when I Zoom the Image-A and drag it to a new location, the problem is when I touch the Image-B, then Image-B automatically moves to the X and Y position of Image-A with same zoom level of Image-A, and viceversa. I need to retain the zoom level and dragged position of all the images individually. Please provide me some solution. Thanks in advance.

    • Hi Manoj,
      You will have to determine which ImageView was clicked. Then, apply the transformations only to that ImageView.

      • Manoj

        Thanks for your reply Jude, I have determined which ImageView has been clicked by getTag() property of the ImageView, how to apply transformations to that particular ImageView, should we do it in MotionEvent.ACTION_DOWN event, Please explain

        • Maintain a mapping between each ImageView and the other objects associated with it, such as Matrix. Then in the case that has the ACTION_DOWN line, set the current reference ImageView entity to the selected ImageView.

    • erick

      Hi, manoj. how did you do the multiple images? Im having a tough time there. I’m able to transfrom the image with the help of this tutorial but when I add a second image, it seems that the 1st image that I added is now untouchable because of the FILL_PARENT. and when I set it on WRAP_CONTENT, I can only transform it on its own height and width. How can I access the 1st image again? hope you can help.

    • Hey Aditya, does your phone support three fingers? In the example, I’ve set it to rotate only in the presence of three pointers.

  14. Ken

    Any tips on dealing with border cases? I’m trying to restrict the images from being to be scrolled completely off screen.

    • Ken,
      Absolutely. You can use the methods getX() and getY() on the ImageView object. These two methods return the position of the top left corner of the ImageView.

      Then you have two cases:
      1. If the ImageView is going out from the left or the top: return from the onTouch() method if the values are negative(the view goes to the extreme left or extreme top)
      2. If the ImageView is going out from the right or the bottom: return from onTouch() if imageView.getX() + view.getLayoutParams().width is greater than your device’s actual resolution(that is, the imageView is at the extreme right). You will have to do the same for the Y axis as well, which will take care of the ImageView going out from the bottom.

      Let me know if you need any further explanation. Would love to help you out.

      • Ken

        Are we actually moving the ImageView when we call setImageMatrix() ? I thought only the image was being moved but not actually the view itself. getX() and getY() on the ImageView object were unchanged when I was testing it.

        • Yes, I forgot about that part. To get the X and Y of the current position of the ImageView, get it from the Matrix. You should get the translation values for X and Y, after calling getValues() on the Matrix.

        • Something like this will get you what you’re looking for:

          float[] values = new float[9];
          int x = values[Matrix.MTRANS_X];
          int y = values[Matrix.MTRANS_Y];

          • Note: You will need to add the ImageView’s getTop() value to the x and getLeft() to the y value to get the actual position of the image inside the ImageView.

        • From

          “It is possible to retrieve the location of a view by invoking the methods getLeft() and getTop(). The former returns the left, or X, coordinate of the rectangle representing the view. The latter returns the top, or Y, coordinate of the rectangle representing the view. These methods both return the location of the view relative to its parent. For instance, when getLeft() returns 20, that means the view is located 20 pixels to the right of the left edge of its direct parent.”

  15. Kevin

    Wow amazing ~ i thought it doesn’t work but when i tried to control by 3 fingers. Rotation worked ~~~
    Appreciate ~ i understood how to make it ~

  16. Angeline

    Hi, I have tried your codes and it works perfectly. But can I know if there is anything I could change in your codes to make the rotation of the image not so sensitive? As a slight tilt of my fingers can cause the image to be rotate 360 degrees.

    • Angeline,
      Have you tried compiling the github source? The rotation in not so sensitive, and it definitely works very well.

      The issue that your facing, very sensitive rotation, is one I face in one of my other apps, and I’ve not found a solution yet to it.

  17. jeet

    its a very useful tutorial but how can i modify this to work on a textview??

    • jeet

      i want to put the textview above imageview(frame layout) thats why i just want to apply these operations on textview and not imageview

  18. lins louis

    nice tutorial..but the rotation not-working in my device..does all device support more than two fingers?..

Comments are closed.