title: Android: How to rotate an element by touching it?
body: <p>I'm trying to rotate a drawable inside a view by touching it and moving the finger. I've come up with several solutions, but none of them feels natural on the device.</p>
  
  <p>Here's my first approach: Depending on where the user touched the screen and in which direction the finger was moved, I'm changing the drawable's rotation, calculated more or less arbitrarily.</p>
  
  <pre><code>private void updateRotation(float x, float y, float oldX, float oldY) {
      int width = getWidth();
      int height = getHeight();
  
      float centerX = width / 2;
      float centerY = height / 2;
  
      float xSpeed = rotationSpeed(x, oldX, width);
      float ySpeed = rotationSpeed(y, oldY, height); 
  
      if ((y &lt; centerY &amp;&amp; x &gt; oldX)
          || (y &gt; centerY &amp;&amp; x &lt; oldX))
          rotation += xSpeed;
      else if ((y &lt; centerY &amp;&amp; x &lt; oldX)
               || (y &gt; centerY &amp;&amp; x &gt; oldX))
          rotation -= xSpeed;
  
      if ((x &gt; centerX &amp;&amp; y &gt; oldY)
          || (x &lt; centerX &amp;&amp; y &lt; oldY))
          rotation += ySpeed;
      else if ((x &gt; centerX &amp;&amp; y &lt; oldY)
               || (x &lt; centerX &amp;&amp; y &gt; oldY))
          rotation -= ySpeed;
  }
  
  private static float rotationSpeed(float pos, float oldPos, float max) {
      return (Math.abs(pos - oldPos) * 180) / max;
  }
  </code></pre>
  
  <p>This approach had a few annoying side effects: Sometimes the drawable would rotate while the finger wasn't moving and the rotation was generally not as fast as the user's finger.</p>
  
  <p>Hence I threw this code away and started with my second approach. I'm using trigonometry to calculate the actual rotation that would be equivalent to the finger movement:</p>
  
  <pre><code>private void updateRotation(float x, float y, float oldX, float oldY) {
      float centerX = getWidth() / 2;
      float centerY = getHeight() / 2;
  
      float a = distance(centerX, centerY, x, y);
      float b = distance(centerX, centerY, oldX, oldY);
      float c = distance(x, y, oldX, oldY);
  
      double r = Math.acos((Math.pow(a, 2) + Math.pow(b, 2) - Math.pow(c, 2))
                           / (2 * a * b));
  
      if ((oldY &lt; centerY &amp;&amp; x &lt; oldX)
          || (oldY &gt; centerY &amp;&amp; x &gt; oldX)
          || (oldX &gt; centerX &amp;&amp; y &lt; oldY)
          || (oldX &lt; centerX &amp;&amp; y &gt; oldY))
          r *= -1; 
  
      rotation += (int) Math.toDegrees(r);
  }
  
  private float distance(float x1, float y1, float x2, float y2) {
      return Math.abs(x1 - x2) + Math.abs(y1 - y2);
  }
  </code></pre>
  
  <p>Although this does sound like the correct solution to me, it's not working well either. Finger movement is sometimes ignored - could the calculation be too expensive? Furthermore, the rotation is still a bit faster than the actual finger movement.</p>
  
  <p>Ideally, if I start rotating the drawable touching a specific point, this very point should stay below the finger at all times. Can you tell me how to achieve this?</p>
  
  <p><strong>Edit:</strong></p>
  
  <p>Here's my adoption of Snailer's suggestion. I had to switch the arguments for the <code>atan2</code> method to rotate into the right direction, now it works great:</p>
  
  <pre><code>private void updateRotation(float x, float y) {
      double r = Math.atan2(x - getWidth() / 2, getHeight() / 2 - y);
      rotation = (int) Math.toDegrees(r);
  }
  </code></pre>