Android8/25/2020

How to Create a Circular Progress Bar in Android Studio

Circular progress bars are commonly used in Android applications to display progress visually in a modern and interactive way.

Examples include:

  • File download progress
  • Fitness tracking
  • Loading indicators
  • Battery percentage
  • Task completion status
  • Dashboard analytics

In this tutorial, we will learn how to create a customizable circular progress bar in Android Studio using:

  • Custom drawable XML
  • Gradient progress effect
  • ProgressBar widget
  • Dynamic progress updates

What We Will Build

In this Android example:

  • Create circular progress bar
  • Add gradient effect
  • Display percentage text
  • Increase and decrease progress dynamically
  • Create modern UI using ConstraintLayout

Step 1 — Create circle.xml Drawable

Create:


res/drawable/circle.xml

Add the following code:


<?xml version="1.0" encoding="utf-8"?>

<layer-list
    xmlns:android=
    "http://schemas.android.com/apk/res/android">

    <item>

        <shape
            android:shape="ring"
            android:thicknessRatio="16"
            android:useLevel="false">

            <solid
                android:color="#DDDDDD"/>

        </shape>

    </item>

    <item>

        <rotate
            android:fromDegrees="270"
            android:toDegrees="270">

            <shape
                android:shape="ring"
                android:thicknessRatio="16"
                android:useLevel="true">

                <gradient
                    android:startColor=
                    "@color/purple_500"

                    android:endColor=
                    "@color/teal_200"

                    android:type="sweep"/>

            </shape>

        </rotate>

    </item>

</layer-list>

How This Drawable Works

This drawable creates:

  • Gray circular background ring
  • Gradient progress ring
  • Sweep animation effect
  • Circular determinate progress style

Step 2 — Add Circular Progress Style

Inside:


res/values/styles.xml

Add:


<style
    name="CircularDeterminateProgressBar">

    <item
        name="android:indeterminateOnly">
        false
    </item>

    <item
        name="android:progressDrawable">
        @drawable/circle
    </item>

    <item
        name="android:indeterminateDrawable">
        @drawable/circle
    </item>

    <item
        name="android:minHeight">
        200dp
    </item>

    <item
        name="android:maxHeight">
        200dp
    </item>

</style>

Step 3 — Create activity_main.xml

Create:


res/layout/activity_main.xml

<?xml version="1.0" encoding="utf-8"?>

<androidx.constraintlayout.widget.ConstraintLayout

    xmlns:android=
    "http://schemas.android.com/apk/res/android"

    xmlns:app=
    "http://schemas.android.com/apk/res-auto"

    android:layout_width="match_parent"

    android:layout_height="match_parent">

    <ProgressBar
        android:id="@+id/progress_bar"

        style=
        "@style/CircularDeterminateProgressBar"

        android:layout_width="200dp"

        android:layout_height="200dp"

        android:max="100"

        app:layout_constraintTop_toTopOf="parent"

        app:layout_constraintBottom_toBottomOf="parent"

        app:layout_constraintStart_toStartOf="parent"

        app:layout_constraintEnd_toEndOf="parent"

        tools:progress="60"/>

    <TextView
        android:id="@+id/text_view_progress"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:textSize="28sp"

        android:textStyle="bold"

        app:layout_constraintTop_toTopOf=
        "@id/progress_bar"

        app:layout_constraintBottom_toBottomOf=
        "@id/progress_bar"

        app:layout_constraintStart_toStartOf=
        "@id/progress_bar"

        app:layout_constraintEnd_toEndOf=
        "@id/progress_bar"

        tools:text="60%"/>

    <Button
        android:id="@+id/button_decr"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:text="-10%"

        app:layout_constraintTop_toBottomOf=
        "@id/progress_bar"

        app:layout_constraintStart_toStartOf=
        "@id/progress_bar"/>

    <Button
        android:id="@+id/button_incr"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:text="+10%"

        app:layout_constraintTop_toBottomOf=
        "@id/progress_bar"

        app:layout_constraintEnd_toEndOf=
        "@id/progress_bar"/>

</androidx.constraintlayout.widget.ConstraintLayout>

Step 4 — Create MainActivity.java

Create:


MainActivity.java

package com.example.circularprogressbar;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;

public class MainActivity
        extends AppCompatActivity {

    private Button buttonIncr;

    private Button buttonDecr;

    private ProgressBar progressBar;

    private TextView textViewProgress;

    private int progress = 0;

    @Override
    protected void onCreate(
            Bundle savedInstanceState
    ) {

        super.onCreate(savedInstanceState);

        setContentView(
                R.layout.activity_main
        );

        buttonIncr =
                findViewById(R.id.button_incr);

        buttonDecr =
                findViewById(R.id.button_decr);

        progressBar =
                findViewById(R.id.progress_bar);

        textViewProgress =
                findViewById(
                        R.id.text_view_progress
                );

        updateProgressBar();

        buttonIncr.setOnClickListener(
                new View.OnClickListener() {

            @Override
            public void onClick(View view) {

                if (progress <= 90) {

                    progress += 10;

                    updateProgressBar();
                }
            }
        });

        buttonDecr.setOnClickListener(
                new View.OnClickListener() {

            @Override
            public void onClick(View view) {

                if (progress >= 10) {

                    progress -= 10;

                    updateProgressBar();
                }
            }
        });
    }

    private void updateProgressBar() {

        progressBar.setProgress(progress);

        textViewProgress.setText(
                progress + "%"
        );
    }
}

How This Circular Progress Bar Works

The workflow is:

  1. Custom ring drawable creates circular shape
  2. Gradient sweep displays progress color
  3. ProgressBar updates dynamically
  4. TextView shows current percentage
  5. Buttons control progress changes

Why Use Circular Progress Bars?

Circular progress indicators:

  • Look modern
  • Improve user experience
  • Save UI space
  • Provide visual feedback clearly

Modern Android Recommendations

Modern Android applications often prefer:

  • Material Progress Indicators
  • Jetpack Compose progress components
  • Lottie animations
  • Animated vector drawables

Material Design Circular Indicator

Google Material Design now recommends:


CircularProgressIndicator

from Material Components library for modern applications.


Common Beginner Mistakes

1. Forgetting max Value

Always set:


android:max="100"

2. Using Large Thickness Ratio

Very thick rings may distort the UI.


3. Updating Progress Outside Main Thread

UI updates must occur on the main thread.


ProgressBar vs CircularProgressIndicator

ProgressBar CircularProgressIndicator
Classic Android widget Material Design component
Custom drawable required Modern styling built-in
Flexible customization Better Material integration

Advanced Customization Ideas

  • Animated progress transitions
  • Gradient animations
  • Custom fonts
  • Percentage labels
  • Loading animations
  • Dynamic colors

FAQ

Can circular progress bars animate smoothly?

Yes. ObjectAnimator and ValueAnimator can animate progress updates smoothly.

Can gradient colors be customized?

Yes. Modify:


android:startColor
android:endColor

inside the drawable XML.

What is the modern recommended approach?

Material CircularProgressIndicator or Jetpack Compose progress indicators are recommended for modern Android applications.


Conclusion

Circular progress bars provide visually attractive and interactive progress indicators for Android applications.

Using custom drawable XML with ProgressBar allows developers to build highly customizable circular indicators with gradients and animations.

Modern Android applications should combine Material Design components, smooth animations, and lifecycle-aware updates for professional UI experiences.


About the Author

Salil Jha is a Full Stack and Mobile Developer specializing in Android, React Native, fintech systems, scalable SaaS platforms, and developer tooling products.

CodeChain Dev — Build Modern Products. Solve Real Problems.

Deep Structural Diagnostics.

Mastering JSON is only the first step. Use our industrial-grade workbench to format, validate, and synthesize models for your production APIs.