Canvas Android. Moving and rotating a bitmap in a circular path based on tangency?

Is it possible to move and rotate an image along a circular path based on a touch event like this: enter image description here

I have looked at this question: Moving an image in a circular motion based on touch events in android But that only tells me how to move the image in a circle and not rotate it.

+3


source to share


1 answer


Update: Full example is hosted on GitHub at https://github.com/jselbie/xkcdclock

Every time you receive a touch event, grab the x, y coordinates of the point and calculate the rotation angle from the center of the bitmap. Use this value to determine how much to rotate the bitmap you want to render.

Let's first assume a logical coordinate system in which the center point of your element above is at (0,0) in x, y space.

Therefore, the angle (in degrees) between any tangent point relative to the center can be calculated as follows:

double ComputeAngle(float x, float y)
{
    final double RADS_TO_DEGREES = 360 / (java.lang.Math.PI*2);
    double result = java.lang.Math.atan2(y,x) * RADS_TO_DEGREES;

    if (result < 0)
    {
        result = 360 + result;
    }

    return result;
}

      

Note - normalizing negative angles to positive angles. Therefore, if the touch point is (20,20), this function will return 45 degrees higher.

To use this method, your activity will require the following member variables:



float _refX;   // x coordinate of last touch event
float _refY;   // y coordinate or last touch event
float _rotation;  // what angle should the source image be rotated at
float _centerX;         // the actual center coordinate of the canvas we are drawing on
float _centerY;         // the actual center coordinate of the canvas we are drawing on

      

Now let's see how to keep track of the touch coordinates so that we can always have the "_rotation" variable updated.

So our Android "touch handler" will look something like this:

boolean onTouch(View v, MotionEvent event)
{
    int action = event.getAction();
    int actionmasked = event.getActionMasked();

    if (!_initialized)
    {
        // if we haven't computed _centerX and _centerY yet, just bail
        return false;
    }

    if (actionmasked == MotionEvent.ACTION_DOWN)
    {
        _refX = event.getX();
        _refY = event.getY();
        return true;
    }
    else if (actionmasked == MotionEvent.ACTION_MOVE)
    {

        // normalize our touch event X and Y coordinates to be relative to the center coordinate
        float x = event.getX() - _centerX;
        float y =  _centerY - event.getY();

        if ((x != 0) && (y != 0))
        {
            double angleB = ComputeAngle(x, y);

            x = _refX - _centerX;
            y = _centerY - _refY;
            double angleA = ComputeAngle(x,y);

            _rotation += (float)(angleA - angleB);

            this.invalidate();  // tell the view to redraw itself
        }
    }    

      

There are some small details in there, such as drawing a real bitmap. You can also handle the ACTION_UP and ACTION_CANCEL events to normalize the _rotation to always be between 0 and 360. But the main point is that the above code is the basis for calculating the _rotation, whereby your Bitmap should be drawn on the view. Something like the following:

void DrawBitmapInCenter(Bitmap bmp, float scale, float rotation, Canvas canvas)
{
    canvas.save();
    canvas.translate(canvas.getWidth()/2, canvas.getHeight()/2);
    canvas.scale(scale, scale);
    canvas.rotate(rotation);
    canvas.translate(-bmp.getWidth()/2, -bmp.getHeight()/2);
    canvas.drawBitmap(bmp, 0, 0, _paint);
    canvas.restore();
}

      

+5


source







All Articles