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:
- Custom ring drawable creates circular shape
- Gradient sweep displays progress color
- ProgressBar updates dynamically
- TextView shows current percentage
- 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.