Kyle Banks

Creating an Infinitely Rotating ImageView on Android

Written by @kylewbanks on Jul 30, 2016.

Recently I wanted to add an animation to an ImageView to infinitely rotate in place, in order to create a custom loading spinner. The requirements were simple enough that customizing the ProgressBar view wasn’t necessary, and we didn’t need anything fancy like a GIF.

The process is straightforward, just define a RotateAnimation, where the view will rotate with an anchor at the center of itself, with a 360 degree rotation, infinitely:

RotateAnimation rotate = new RotateAnimation(
    0, 360, 
    Animation.RELATIVE_TO_SELF, 0.5f, 
    Animation.RELATIVE_TO_SELF, 0.5f
);
rotate.setDuration(duration);
rotate.setRepeatCount(Animation.INFINITE);
imageView.startAnimation(rotate);

In my case, I wanted to take it a step further and create a reusable view that I can drop anywhere in the application, without having to redefine the animation. I created an ImageView subclass, like so:

public class LoadingSpinner extends ImageView {

    private static final int ROTATE_ANIMATION_DURATION = 800;
    private static final int IMAGE_RESOURCE_ID = R.drawable.loading_image;

    public LoadingSpinner(Context context) {
        super(context, null);
    }

    public LoadingSpinner(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public LoadingSpinner(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();

        // Set and scale the image
        setImageResource(IMAGE_RESOURCE_ID);

        // Start the animation
        startAnimation();
    }

    /**
     * Starts the rotate animation.
     */
    private void startAnimation() {
        clearAnimation();

        RotateAnimation rotate = new RotateAnimation(
            0, 360, 
            Animation.RELATIVE_TO_SELF, 0.5f, 
            Animation.RELATIVE_TO_SELF, 0.5f
        );
        rotate.setDuration(ROTATE_ANIMATION_DURATION);
        rotate.setRepeatCount(Animation.INFINITE);
        startAnimation(rotate);
    }

    @Override
    public void setVisibility(int visibility) {
        super.setVisibility(visibility);

        if (visibility == View.VISIBLE) {
            startAnimation();
        } else {
            clearAnimation();
        }
    }
}

The main piece here is in onFinishInflate we set the image resource and call startAnimation, which clears any existing animation, defines the RotateAnimation, and starts the animation on the LoadingSpinner instance.

You’ll notice that I also overrode the setVisibility method to stop and start the animation based on if the view is VISIBLE. This was necessary because the RotateAnimation seems to set the visibility of it’s target view, so hiding the ImageView became impossible.

With the custom LoadingSpinner defined, it can be dropped into any layout:

<com.example.LoadingSpinner
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"/>

Or programmatically:

LoadingSpinner loadingSpinner = new LoadingSpinner(context);
layout.addView(loadingSpinner);

For more Android animations, check out my post on Implementing Google Plus Style ListView Animations or Animating Toolbar, TabLayout, FloatingActionButton and StatusBar Background Colors.

Let me know if this post was helpful on Twitter @kylewbanks or down below!