title: rotate and resize the image view with single finger in android
body: <p>I am developing an app which has feature that resizing and rotating the imageview by dragging its bottom right corner button.</p>
  
  <p>I saw one app which has feature that if we drag the bottom right corner button diagonally imageview size had resized or else if we drag the button left or right side direction imageview had rotated as per direction. I wish to implement this feature in my app</p>
  
  <p>I am struggling to implement single finger rotation as well as resizing the imageview.</p>
  
  <p>Please guide me in right way.<img src="https://i.stack.imgur.com/8JQAn.png" alt="enter image description here"></p>
  
  <hr>
  
  <p>I am trying this code, and try to apply zoom and rotate but not able to do please help me.
  belove code to do zoom and rotate finger base action.</p>
  
  <pre><code>public class ScaleActivity extends Activity {
  
  ViewGroup lLayout;
  static ImageView img, backgrndImg;
  Canvas mCanvas;
  float d;
  private float mAspectQuotient;
  @Override
  protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);
  
      lLayout = (FrameLayout) findViewById(R.id.lLayout);
  
      final CropView cv = new CropView(this);
      lLayout.addView(cv);
  
  }
  
  @Override
  public boolean onCreateOptionsMenu(Menu menu) {
      // Inflate the menu; this adds items to the action bar if it is present.
      getMenuInflater().inflate(R.menu.main, menu);
      return true;
  }
  
  public class CropView extends ImageView {
      private static final int SELECTION_RECT_PAINT_COLOR = 0xFF000000;
      private static final int SELECTION_RECT_FILL_COLOR = 0x70FFFFFF;
      private static final int TOUCH_TOLERANCE = 25;
      private static final int xInc = 25;
      private static final int yInc = 25;
      Paint paint = new Paint();
      private int initial_size = 200;
      private Point leftTop, rightBottom, center, previous, currentPoint,
              rectPos;
      private Paint fillPaint;
      private Paint rectPaint;
      protected Rect selection, dest;
      private boolean isAffectedBottom = false;
      Bitmap bitmap, backgroundBitmap;
      Rect rectf;
      Rect knobRect;
      private Context mContext;
      int width, height;
      private Matrix matrix = new Matrix();
      Bitmap resizedBitmap;
  
      // Adding parent class constructors
      public CropView(Context context) {
          super(context);
  
          mContext = context;
  
          backgroundBitmap = BitmapFactory.decodeResource(getContext()
                  .getResources(), R.drawable.toast_bkgrd);
          bitmap = BitmapFactory.decodeResource(getContext().getResources(),
                  R.drawable.aviary_adjust_knob);
  
          rectPaint = new Paint();
          rectPaint.setStyle(Style.STROKE);
          rectPaint.setColor(SELECTION_RECT_PAINT_COLOR);
          fillPaint = new Paint();
          fillPaint.setStyle(Style.FILL);
          fillPaint.setColor(SELECTION_RECT_FILL_COLOR);
          currentPoint = new Point(getWidth() / 2, getHeight() / 2);
          width = backgroundBitmap.getWidth();
          height = backgroundBitmap.getHeight();
          initCropView();
      }
  
      public CropView(Context context, AttributeSet attrs) {
          super(context, attrs, 0);
          initCropView();
      }
  
      public CropView(Context context, AttributeSet attrs, int defStyle) {
          super(context, attrs, defStyle);
          initCropView();
      }
  
      @SuppressLint("DrawAllocation")
      @Override
      protected void onDraw(Canvas canvas) {
          super.onDraw(canvas);
          mCanvas = canvas;
          if (leftTop.equals(0, 0))
              resetPoints();
          mCanvas.save();
          resizedBitmap = Bitmap.createBitmap(backgroundBitmap, 0, 0,
                  backgroundBitmap.getWidth(), backgroundBitmap.getHeight(),
                  matrix, true);
          // mCanvas.drawBitmap(backgroundBitmap, matrix, rectPaint);
          mCanvas.drawBitmap(resizedBitmap, null, selection, rectPaint);
          mCanvas.drawBitmap(bitmap, selection.right - 25,
                  selection.bottom - 25, null);
          rectPos.set(selection.left, selection.top);
  
          mCanvas.restore();
  
      }
  
  
      @Override
      public boolean onTouchEvent(MotionEvent event) {
          int eventaction = event.getAction();
          switch (eventaction) {
          case MotionEvent.ACTION_DOWN:
              touchDown((int) event.getX(), (int) event.getY());
              previous.set((int) event.getX(), (int) event.getY());
  
              break;
          case MotionEvent.ACTION_MOVE:
              touchMove((int) event.getX(), (int) event.getY());
  
              if (isActionInsideRectangle(event.getX(), event.getY())
                      &amp;&amp; !isAffectedBottom) {
                  drag((int) event.getX(), (int) event.getY());
                  invalidate(); // redraw rectangle
                  previous.set((int) event.getX(), (int) event.getY());
              }
              previous.set((int) event.getX(), (int) event.getY());
              break;
          case MotionEvent.ACTION_UP:
              touchUp((int) event.getX(), (int) event.getY());
              previous = new Point();
              break;
          }
          return true;
      }
  
      private void initCropView() {
          paint.setColor(Color.WHITE);
          paint.setStyle(Style.STROKE);
          paint.setStrokeWidth(5);
          leftTop = new Point();
          rightBottom = new Point();
          center = new Point();
          previous = new Point();
          rectPos = new Point();
  
      }
  
      public void resetPoints() {
          center.set(getWidth() / 2, getHeight() / 2);
          leftTop.set((getWidth() - initial_size) / 2,
                  (getHeight() - initial_size) / 2);
          rightBottom.set(leftTop.x + initial_size, leftTop.y + initial_size);
          selection = new Rect(leftTop.x, leftTop.y, rightBottom.x,
                  rightBottom.y);
          knobRect = new Rect(selection.right, selection.bottom,
                  bitmap.getWidth(), bitmap.getHeight());
          dest = selection;
      }
  
      private boolean isActionInsideRectangle(float x, float y) {
          int buffer = 10;
          return (x &gt;= (selection.left) &amp;&amp; x &lt;= (selection.right)
                  &amp;&amp; y &gt;= (selection.top) &amp;&amp; y &lt;= (selection.bottom)) ? true
                  : false;
      }
  
      void touchDown(int x, int y) {
  
          System.out.println("selection " + selection);
          int dx = (previous.x - x) / 2;
          int dy = (previous.y - y) / 2;
          // d= rotation(dx,dy);
          currentPoint.set(x, y);
          if (pointsAreClose(x, y, selection.right, selection.bottom)) {
              isAffectedBottom = true;
              System.out.println("isAffectedBottom " + isAffectedBottom);
          }
      }
  
      void touchMove(int x, int y) {
          currentPoint.set(x, y);
          if (isAffectedBottom) {
              int dx = (previous.x - x) / 2;
              int dy = (previous.y - y) / 2;
              double startAngle = getAngle(previous.x, previous.y);
  
              double currentAngle = getAngle(x, y);
  
              matrix.postRotate((float) (startAngle - currentAngle),
                      selection.width() / 2.0f, selection.height() / 2.0f);
              // selection.inset(dx, dy);             
              invalidate();
          }
      }
  
      void touchUp(int x, int y) {
          currentPoint.set(x, y);
          isAffectedBottom = false;
      }
  
      private boolean pointsAreClose(float x1, float y1, float x2, float y2) {
          return Math.hypot(x1 - x2, y1 - y2) &lt; TOUCH_TOLERANCE;
      }
  
      private void drag(int x, int y) {
          int movement;
          movement = x - previous.x;
          int movementY = y - previous.y;
          selection.set(selection.left + movement, selection.top + movementY,
                  selection.right + movement, selection.bottom + movementY);
          selection.sort();
          invalidate();
      }
  
  
      /**
       * Calculate the degree to be rotated by.
       * 
       * @param event
       * @return Degrees
       */
      // private float rotation(float dx, float dy) {
      //
      // // double delta_x = (dx);
      // // double delta_y = (dy);
      // double radians = Math.atan2((selection.left) - (previous.y),
      // (selection.top) - (previous.x));
      // double radians2 = Math.atan2((selection.left) - (dy),
      // (selection.top) - (dx));
      //
      // System.out.println("radians" + radians);
      // System.out.println("" + radians2);
      // System.out.println("radians2-radians" + (radians2 - radians));
      // System.out.println(Math.toDegrees(radians2 - radians));
      // return (float) Math.toDegrees(radians2 - radians);
      //
      // }
  
      private double getAngle(double xTouch, double yTouch) {
          double x = xTouch - (getWidth() / 2d);
          double y = getHeight() - yTouch - (getHeight() / 2d);
  
          switch (getQuadrant(x, y)) {
          case 1:
              System.out.println("1");
              return Math.asin(y / Math.hypot(x, y)) * 180 / Math.PI;
  
          case 2:
          case 3:
              System.out.println("32");
              return 180 - (Math.asin(y / Math.hypot(x, y)) * 180 / Math.PI);
  
          case 4:
              System.out.println("4");
              return 360 + Math.asin(y / Math.hypot(x, y)) * 180 / Math.PI;
  
          default:
              // ignore, does not happen
              return 0;
          }
      }
  
      /**
       * @return The selected quadrant.
       */
      private int getQuadrant(double x, double y) {
          if (x &gt;= 0) {
              return y &gt;= 0 ? 1 : 4;
          } else {
              return y &gt;= 0 ? 2 : 3;
          }
      }
  }
  
  }
  </code></pre>