Indeterminate ProgressBar with custom image

Updated in Android

THe most common way to inform user that your app is doing something in the background is to show a ProgressBar to the user.

There are two types of ProgressBars available. The progress bar can either show distinct value like 34/76 or it can be indeterminate. In this tutorial we customize the indeterminate ProgressBar.

In the most simplest case indeterminate ProgressBar is written like this:

<ProgressBar
    android:id="@+id/progress"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:indeterminate="true" />

But if you want to show a custom drawable instead of the default one, you can use the indeterminateDrawable attribute:

<ProgressBar
    ...
    android:indeterminateDrawable="@drawable/indeterminate_progress"
    ... />

You can use any drawable as the indeterminate drawable, but in order to make it look like something is happening, it makes sense to animate it. I personally prefer using xml drawables here.

For example very simple rotating indeterminate progress image can be achieved with this:

<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
    android:fromDegrees="0"
    android:pivotX="50%"
    android:pivotY="50%"
    android:toDegrees="360">
    <shape
        android:innerRadiusRatio="3"
        android:shape="ring"
        android:thicknessRatio="10"
        android:useLevel="false">

        <gradient
            android:angle="0"
            android:endColor="#008577"
            android:startColor="#00000000"
            android:type="sweep"
            android:useLevel="false" />
    </shape>
</rotate>

Since drawable xml supports layer lists, you can combine two or more shapes or drawable instances to create complex image:

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:bottom="5dp"
        android:drawable="@android:drawable/ic_delete"
        android:left="5dp"
        android:right="5dp"
        android:top="5dp" />
    <item>
        <rotate
            android:fromDegrees="0"
            android:pivotX="50%"
            android:pivotY="50%"
            android:toDegrees="360">
            <shape
                android:innerRadiusRatio="3"
                android:shape="ring"
                android:thicknessRatio="10"
                android:useLevel="false">

                <gradient
                    android:angle="0"
                    android:endColor="@color/colorPrimary"
                    android:startColor="@android:color/transparent"
                    android:type="sweep"
                    android:useLevel="false" />
            </shape>
        </rotate>
    </item>
</layer-list>

If you want to change the rotation speed, there’s two things you can do. You can either change the amount of degrees the rotation makes or you can set the animation time.

To change the rotation just change the degrees:

<rotate xmlns:android="http://schemas.android.com/apk/res/android"
    android:fromDegrees="0"
    ...
    android:toDegrees="1080">
    ...
</rotate>

Remember to use multiples of 360 to make sure the rotation isn’t jumpy. The time it takes for the rotation to happen is listed below:

Degrees Rotation time
360 4s
720 2s
1080 1.33s
1440 1s

Or you can set the exact time in the layout xml with indeterminateDuration:

<ProgressBar
    ...
    android:indeterminateDuration="1500"
    ... />

indeterminateDuration takes milliseconds as the parameter, so in the above ProgressBar one full rotation takes 1.5 seconds.