Animate rotation of an image in Android

12,781

Solution 1

In your onCreate() do

Matrix matrix = new Matrix();

And in onDraw

float angle = (float) (System.currentTimeMillis() % ROTATE_TIME_MILLIS) 
   / ROTATE_TIME_MILLIS * 360;
matrix.reset();
matrix.postTranslate(-source.getWidth() / 2, -source.getHeight() / 2);
matrix.postRotate(angle);
matrix.postTranslate(centerX, centerY)
canvas.drawBitmap(source, matrix, null);
invalidate(); // Cause a re-draw

ROTATE_TIME_MILLIS is the full circle time, e.g. 2000 is 2 seconds.

Solution 2

Make an XML class (suppose: rotate.xml) and place it in res/anim folder and then write the following code in it:

<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
    android:fromDegrees="0"
    android:interpolator="@android:anim/linear_interpolator"
    android:pivotX="50%"
    android:pivotY="50%"
    android:repeatCount="infinite"
    android:toDegrees="360" />

Then in your java class, do the following in OnCreate:

final Animation a = AnimationUtils.loadAnimation(CustomActivity.this,
                R.anim.rotate);
        a.setDuration(3000);
        gear00.startAnimation(a);

OR

To do it using bitmap, I hope the following sequence of code helps you:

Bitmap targetBitmap = Bitmap.createBitmap(targetWidth, targetHeight, config);
Canvas canvas = new Canvas(targetBitmap);
Matrix matrix = new Matrix();
matrix.setRotate(mRotation,source.getWidth()/2,source.getHeight()/2);
canvas.drawBitmap(source, matrix, new Paint());

If you check the following method from:

~frameworks\base\graphics\java\android\graphics\Bitmap.java

public static Bitmap createBitmap(Bitmap source, int x, int y, int width, int height,
        Matrix m, boolean filter)

this would explain what it does with rotation and translate.

Solution 3

I want to rotate a custom image as progress dialog in my application. You can use the code below to rotate an image:

RotateAnimation anim = new RotateAnimation(0.0f, 360.0f , 
Animation.RELATIVE_TO_SELF, .5f, Animation.RELATIVE_TO_SELF, .5f);
anim.setInterpolator(new LinearInterpolator());
anim.setRepeatCount(Animation.INFINITE);
anim.setDuration(1000);
imageView.setAnimation(anim);
imageView.startAnimation(anim);

Solution 4

Two things before the code:

  1. You can't use imageview at all at all? Cause you could link it to a canvas and use a bitmap, but it is still an imageview.
  2. I believe the main issue you are having is the other answer is not animating it and you are missing the call to invalidate() the view and redraw it as rotated.

So there are two approaches: 1st is with the imageview, personally I think it is easier and nicer. Below is a method in my activity class and mLittleChef is an ImageView.

public void doCanvas(){
    //Create our resources
    Bitmap bitmap = Bitmap.createBitmap(mLittleChef.getWidth(), mLittleChef.getHeight(), Bitmap.Config.ARGB_8888);
    final Canvas canvas = new Canvas(bitmap);
    final Bitmap chefBitmap = BitmapFactory.decodeResource(getResources(),R.drawable.dish_special);

    //Link the canvas to our ImageView
    mLittleChef.setImageBitmap(bitmap);

    ValueAnimator animation= ValueAnimator.ofFloat(0, 359, 129, 186);
    animation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            float value = (Float) animation.getAnimatedValue();
            //Clear the canvas
            canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
            canvas.save();
            canvas.rotate(value, canvas.getWidth()/2, canvas.getHeight()/2);
            canvas.drawBitmap(chefBitmap, 0, 0, null);
            canvas.restore();
            mLittleChef.invalidate();
        }
    });
    animation.setInterpolator(new LinearInterpolator());
    animation.setDuration(1000);
    animation.start();
}

The other way to do it is with a custom canvas class. Instead of an ImageView, I create my own custom view class for ExampleDrawView mLittleChefDraw; in my layout. You will probably have to monkey with this one a bit to get exactly what you are looking for in terms of rotation, I made it just do a 360 degree turn using the middle of the canvas as the pivot point.

 public class ExampleDrawView extends View {

Bitmap bitmap;
Float mRotate= 0f;
Handler h;
//State variables
final int STATE_PAUSE = 2;
final int STATE_ROTATE = 3;
int STATE_CURRENT;

public ExampleDrawView(Context context, AttributeSet attrs) {
    super(context, attrs);
    h = new Handler();
    bitmap= BitmapFactory.decodeResource(getResources(), R.drawable.dish_special);
    STATE_CURRENT= STATE_PAUSE;
}

Runnable move = new Runnable() {
    @Override
    public void run() {
        switch (STATE_CURRENT){
        case STATE_ROTATE:
            if (mRotate<360){
                mRotate++;
                invalidate();
            }else{
                STATE_CURRENT= STATE_PAUSE;
            }
            h.postDelayed(move, 20);
            break;
        }               
    }
};

public void startDrawing(){
    if(STATE_CURRENT == STATE_PAUSE){
        STATE_CURRENT= STATE_ROTATE;
        mRotate=(float) 0;
        h.postDelayed(move, 20);
    }
}

@Override
protected void onDraw(Canvas canvas){
    super.onDraw(canvas);
    //change your rotate point here, i just made it the middle of the canvas
    canvas.rotate(mRotate,getWidth()/2,getHeight()/2);
    canvas.drawBitmap(bitmap, 0, 0, null);
}

}

And then back in the activity call this to start it:

public void doCanvasCustomView(){
    mLittleChefDraw.startDrawing();
}
Share:
12,781
rmoh21
Author by

rmoh21

Updated on June 25, 2022

Comments

  • rmoh21
    rmoh21 almost 2 years
    • I have a gear image which I want to continuously rotate about a fixed point.

    • Earlier I was accomplishing this by including the image in my Android class as an ImageView and applying a RotateAnimation to it.

      @InjectView(R.id.gear00)              ImageView gear00;
      RotateAnimation ra07 = new RotateAnimation(0, 359, 129, 186);
      ra07.setDuration(10000);
      ra07.setRepeatCount(RotateAnimation.INFINITE);
      ra07.setInterpolator(new LinearInterpolator());
      gear00.setAnimation(ra07);
      

    Basically, I was injecting the ImageView into the class and applying a rotation animation.

    However, I dont have the luxury of using an ImageView anymore. I have to use a Bitmap and rotate it on the canvas.

    How can I go about accomplishing what I was doing earlier in the onDraw() method with a bitmap rotating about a fixed point continiously on the canvas?

    Edit1:

    I tried one of the suggestions mentioned below my code looks a little like the following

    in onCreate():

    Matrix matrix = new Matrix();
    matrix.setRotate(10, 100, 200);
    

    Then in onDraw() (where gear00Scaled is a bitmap to be rotated on the canvas):

    canvas.drawBitmap(gear00Scaled, matrix, new Paint());

    Another method I tried involved saving the canvas, rotating it, then restoring it:

    canvas.save();
    canvas.rotate(10);
    canvas.drawBitmap(gear00Scaled, 100, 200, null);
    canvas.restore();

    Neither seem to be working though!