Last updated on: May 27, 2023
In this tutorial, I’m going to show you how to make a Custom Progress Dialog for your Android app.
A Progress Dialog is a dialog with a progress indicator and text message.
Progress Dialog is useful while doing some task on your app that needs time to complete, like getting data from a server, because you don’t want to leave your users staring at their screens without letting them know that something is happening in the background.
Contents
Let’s get started!
In this example, we’re going to use CardView to give our Progress Dialog nice rounded corners. If you don’t want this, skip this step and use RelativeLayout instead.
Add the CardView dependency at the module-level of the build.gradle:
// ...
dependencies {
// ...
implementation "androidx.cardview:cardview:1.0.0"
// ...
}
Code language: Swift (swift)
Making the Custom Progress Dialog Layout
Go to res > layout and create the Custom Progress Dialog layout (progress_dialog_view.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:id="@+id/cp_bg_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#00000000"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<androidx.cardview.widget.CardView
android:id="@+id/cp_cardview"
android:layout_width="150dp"
android:layout_height="150dp"
app:cardBackgroundColor="#00000000"
app:cardCornerRadius="16dp"
app:cardElevation="0dp"
app:cardMaxElevation="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/cp_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:gravity="center">
<ProgressBar
android:id="@+id/cp_pbar"
android:layout_width="match_parent"
android:layout_height="45dp"
android:layout_gravity="center"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/cp_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="15dp"
android:text=""
android:textColor="@android:color/white"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>
</androidx.constraintlayout.widget.ConstraintLayout>
Code language: HTML, XML (xml)
Creating the Custom Progress Dialog
Now, create the Kotlin class, named CustomProgressDialog.kt, and paste the following code inside:
class CustomProgressDialog(context: Context) {
private var dialog: CustomDialog
private var cpTitle: TextView
private var cpCardView: CardView
private var progressBar: ProgressBar
fun start(title: String = "") {
cpTitle.text = title
dialog.show()
}
fun stop() {
dialog.dismiss()
}
init {
val inflater = (context as Activity).layoutInflater
val view = inflater.inflate(R.layout.progress_dialog_view, null)
cpTitle = view.findViewById(R.id.cp_title)
cpCardView = view.findViewById(R.id.cp_cardview)
progressBar = view.findViewById(R.id.cp_pbar)
// Card Color
cpCardView.setCardBackgroundColor(Color.parseColor("#70000000"))
// Progress Bar Color
setColorFilter(
progressBar.indeterminateDrawable,
ResourcesCompat.getColor(context.resources, R.color.colorPrimary, null)
)
// Text Color
cpTitle.setTextColor(Color.WHITE)
// Custom Dialog initialization
dialog = CustomDialog(context)
dialog.setContentView(view)
}
private fun setColorFilter(drawable: Drawable, color: Int) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
drawable.colorFilter = BlendModeColorFilter(color, BlendMode.SRC_ATOP)
} else {
@Suppress("DEPRECATION")
drawable.setColorFilter(color, PorterDuff.Mode.SRC_ATOP)
}
}
class CustomDialog(context: Context) : Dialog(context, R.style.CustomDialogTheme) {
init {
// Set Semi-Transparent Color for Dialog Background
window?.decorView?.rootView?.setBackgroundResource(R.color.dialogBackground)
window?.decorView?.setOnApplyWindowInsetsListener { _, insets ->
insets.consumeSystemWindowInsets()
}
}
}
}
Now, go to res > values > styles.xml to set the theme for the Dialog:
<resources>
<!-- Other Themes -->
<style name="CustomDialogTheme">
<item name="android:windowBackground">@android:color/transparent</item>
</style>
</resources>
Code language: HTML, XML (xml)
Using the Custom Progress Dialog
To use it, declare the class CustomProgressDialog at the beginning of your Activity:
class MainActivity : AppCompatActivity() {
private val progressDialog by lazy { CustomProgressDialog(this) }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// ...
}
}
Code language: Kotlin (kotlin)
… and show the Dialog with a title or not…
class MainActivity : AppCompatActivity() {
private val progressDialog by lazy { CustomProgressDialog(this) }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val startButton = findViewById<Button>(R.id.start_btn)
startButton.setOnClickListener {
// Show progress dialog with title
progressDialog.start("Please Wait...")
// Show progress dialog without title
progressDialog.start()
// ...
}
}
}
Code language: Kotlin (kotlin)
… and dismiss it using:
class MainActivity : AppCompatActivity() {
private val progressDialog = CustomProgressDialog()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val startButton = findViewById<Button>(R.id.start_btn)
startButton.setOnClickListener {
// ...
Handler(Looper.getMainLooper()).postDelayed({
// Dismiss progress bar after 4 seconds
progressDialog.stop()
}, 4000)
}
}
}
Code language: Kotlin (kotlin)
You can find the final project here
If you have any questions, please feel free to leave a comment below