Tutorial

Android ProgressBar using Kotlin

Published on August 4, 2022
author

Anupam Chugh

Android ProgressBar using Kotlin

In this tutorial, we’ll discuss and implement ProgressBar in our Android Application using Kotlin.

What is a ProgressBar?

ProgressBar UI element is used to display the Progress on the app screen. We can use a ProgressBar to show the download/upload progress on the app screen.

Progress Bar Types

There are two types of Progress Bar.

  1. Determinate ProgressBar - This is used when you can track and show the progress completed.
  2. Indeterminate ProgressBar - This one goes infinitely until stopped.

A ProgressDialog would hold a ProgressBar inside an Alert Dialog. ProgressDialog is now deprecated since it isn’t a good idea to show long progress in a dialog while blocking the screen.

ProgressBar Attributes

Some of the important attributes of ProgressBar are:

  • android:indeterminate - used to specify the boolean value indicating the type of the ProgressBar
  • android:max - The upper limit of the progress
  • android:min - The lower limit of the progress
  • android:progress - The steps by which the progress would be incremented.
  • android:minWidth and minHeight - Used to define the dimensions of the ProgressBar
  • android:progressBarTint - The tint color of the progress completed of the ProgressBar
  • android:progressBarBackgroundTint - The tint color of the progress completed of the ProgressBar
  • style - Used to set the style of the ProgressBar. By default it is circular. We can set the style as @style/Widget.AppCompat.ProgressBar.Horizontal for the Horizontal ProgressBar
  • android:progressDrawable - Is used to set a drawable for the progress.
  • android:secondaryProgress - Indicates the secondary progress value. This is used when we want to show the sub-downloads/subtasks progress.

The default tint colors are set to the colorAccent defined in the styles.xml.

ProgressBar XML Layout

A basic circular indeterminate ProgressBar XML layout looks like this:

<ProgressBar
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:minHeight="50dp"
        android:minWidth="50dp" />

In the following section, we’ll implement various types of ProgressBars in our Android app using Kotlin.

Android ProgressBar Kotlin App Project Structure

android progressbar kotlin project structure

1. XML Layout Code

The code for the activity_main.xml layout is as follows.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="vertical"
    tools:context=".MainActivity">


    <ProgressBar
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:minHeight="50dp"
        android:minWidth="50dp" />


    <ProgressBar
        style="?android:attr/progressBarStyleHorizontal"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:indeterminate="true"
        android:minHeight="50dp"
        android:minWidth="200dp" />


    <TextView
        android:id="@+id/textViewHorizontalProgress"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="0" />


    <ProgressBar
        android:id="@+id/progressBarHorizontal"
        style="?android:attr/progressBarStyleHorizontal"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:indeterminate="false"
        android:max="100"
        android:minHeight="50dp"
        android:minWidth="200dp"
        android:progress="1"
        android:progressBackgroundTint="@android:color/darker_gray"
        android:progressTint="@color/colorPrimary" />


    <Button
        android:id="@+id/btnProgressBarHorizontal"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="horizontalDeterminate"
        android:text="DETERMINATE HORIZONTAL PROGRESS BAR" />


    <RelativeLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">

        <ProgressBar
            android:id="@+id/progressBarSecondary"
            style="@style/Widget.AppCompat.ProgressBar.Horizontal"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:minHeight="150dp"
            android:padding="8dp"
            android:minWidth="150dp"
            android:progressDrawable="@drawable/progress_states" />

        <TextView
            android:id="@+id/textViewPrimary"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:textColor="#000" />

        <TextView
            android:id="@+id/textViewSecondary"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="25dp"
            android:layout_below="@+id/progressBarSecondary"
            android:textColor="@color/colorPrimaryDark" />


    </RelativeLayout>

    <Button
        android:id="@+id/btnProgressBarSecondary"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="DETERMINATE SECONDARY PROGRESS BAR" />


</LinearLayout>

In the last progress bar, we’ve set a progress drawable on the horizontal ProgressBar. The drawable.xml file is progress_states.xml.

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@android:id/background">
        <shape android:shape="oval">
            <stroke
                android:width="4dp"
                android:color="@color/colorPrimary" />
            <solid android:color="@android:color/white" />
        </shape>
    </item>
    <item android:id="@android:id/secondaryProgress">
        <clip
            android:clipOrientation="vertical"
            android:gravity="bottom">
            <shape android:shape="oval">
                <stroke
                    android:width="4dp"
                    android:color="@android:color/black" />
                <solid android:color="@android:color/white" />
            </shape>
        </clip>
    </item>
    <item android:id="@android:id/progress">
        <clip
            android:clipOrientation="vertical"
            android:gravity="bottom">
            <shape android:shape="oval">
                <stroke
                    android:width="4dp"
                    android:color="@color/colorAccent" />
                <solid android:color="#F288F8" />
            </shape>
        </clip>
    </item>
</layer-list>

In this drawable, we’ve created different states of the drawable. All are circular shaped and each layer would be displayed for the different states - idle, secondary progress, primary progress.

2. Kotlin Main Activity Code

Let’s look at the MainActivity.kt Kotlin class code.

package net.androidly.androidlyprogressbar

import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.os.Handler
import android.view.View
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity() {


    var isStarted = false
    var progressStatus = 0
    var handler: Handler? = null
    var secondaryHandler: Handler? = Handler()
    var primaryProgressStatus = 0
    var secondaryProgressStatus = 0

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)


        handler = Handler(Handler.Callback {
            if (isStarted) {
                progressStatus++
            }
            progressBarHorizontal.progress = progressStatus
            textViewHorizontalProgress.text = "${progressStatus}/${progressBarHorizontal.max}"
            handler?.sendEmptyMessageDelayed(0, 100)

            true
        })

        handler?.sendEmptyMessage(0)


        btnProgressBarSecondary.setOnClickListener {
            primaryProgressStatus = 0
            secondaryProgressStatus = 0

            Thread(Runnable {
                while (primaryProgressStatus < 100) {
                    primaryProgressStatus += 1

                    try {
                        Thread.sleep(1000)
                    } catch (e: InterruptedException) {
                        e.printStackTrace()
                    }

                    startSecondaryProgress()
                    secondaryProgressStatus = 0

                    secondaryHandler?.post {
                        progressBarSecondary.progress = primaryProgressStatus
                        textViewPrimary.text = "Complete $primaryProgressStatus% of 100"

                        if (primaryProgressStatus == 100) {
                            textViewPrimary.text = "All tasks completed"
                        }
                    }
                }
            }).start()
        }

    }

    fun startSecondaryProgress() {
        Thread(Runnable {
            while (secondaryProgressStatus < 100) {
                secondaryProgressStatus += 1

                try {
                    Thread.sleep(10)
                } catch (e: InterruptedException) {
                    e.printStackTrace()
                }

                secondaryHandler?.post {
                    progressBarSecondary.setSecondaryProgress(secondaryProgressStatus)
                    textViewSecondary.setText("Current task progress\n$secondaryProgressStatus% of 100")

                    if (secondaryProgressStatus == 100) {
                        textViewSecondary.setText("Single task complete.")
                    }
                }
            }
        }).start()
    }

    fun horizontalDeterminate(view: View) {
        isStarted = !isStarted
    }

}

The horizontalDeterminate Kotlin function is triggered when the first button is clicked. It is used to start/stop Horizontal ProgressBar. A Handler is associated with a single thread. It is used to send messages to the Thread. The btnProgressBarSecondary click triggers the second progress bar. We have created two handlers - one for the normal progress and second for the subtasks. In each of them, we are setting the thread to sleep. For the secondary thread, the sleep time is 1/100 of the primary progress thread. The progress value is displayed on the TextView. Output: android progress bar kotlin app output

You can download the project from the following link: AndroidlyProgressBar

Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.

Learn more about our products

About the authors
Default avatar
Anupam Chugh

author

While we believe that this content benefits our community, we have not yet thoroughly reviewed it. If you have any suggestions for improvements, please let us know by clicking the “report an issue“ button at the bottom of the tutorial.

Still looking for an answer?

Ask a questionSearch for more help

Was this helpful?
 
JournalDev
DigitalOcean Employee
DigitalOcean Employee badge
September 15, 2020

Thanks, had some problems with v7 compatibility, but then it worked fine. Thanks very much from Karcsi from Hungary

- karcsi halasz

    Try DigitalOcean for free

    Click below to sign up and get $200 of credit to try our products over 60 days!

    Sign up

    Join the Tech Talk
    Success! Thank you! Please check your email for further details.

    Please complete your information!

    Become a contributor for community

    Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.

    DigitalOcean Documentation

    Full documentation for every DigitalOcean product.

    Resources for startups and SMBs

    The Wave has everything you need to know about building a business, from raising funding to marketing your product.

    Get our newsletter

    Stay up to date by signing up for DigitalOcean’s Infrastructure as a Newsletter.

    New accounts only. By submitting your email you agree to our Privacy Policy

    The developer cloud

    Scale up as you grow — whether you're running one virtual machine or ten thousand.

    Get started for free

    Sign up and get $200 in credit for your first 60 days with DigitalOcean.*

    *This promotional offer applies to new accounts only.