The scenario is to display progress in a ProgressBar and the percentage in a TextView. Once the download is complete, hide the ProgressView and display a message in the TextView. To reference the XML elements we will be using ViewBinding.
Create Android Application Project
Create Android Application Project with following properties:
New Project Template | Empty Activity |
---|---|
Project Name | Progress Demo |
Package Name | com.pcsalt.example.progressdemo |
Language | Kotlin |
Minimum SDK | API 21 : 5.0 (Lollipop) |
Use legacy android.support libraries | Uncheck |
Prepare layout screens
To display the progress we are going to use one TextView and obviously one ProgressBar. The TextView will display the progress percent and same will reflect in the ProgressBar. And once the progress reaches 100% we are going to hide the ProgressView and display a message in the TextView.
Note: Make sure that you have given Horizontal style to the ProgressBar i.e. @style/Widget.AppCompat.ProgressBar.Horizontal
Otherwise it won't work.
Note: Make sure to put max property in ProgressBar. ProgressBar uses value of max and progress to calculate percentage and display the progress. By default the max is set to 100.
<?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">
<TextView
android:id="@+id/tv_progress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ProgressBar
android:id="@+id/pb_details"
style="@style/Widget.AppCompat.ProgressBar.Horizontal"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:max="100"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_progress" />
</androidx.constraintlayout.widget.ConstraintLayout>
Enable ViewBinding
To enable ViewBinding, open the app level build.gradle i.e. app/build.gradle. In the file put the following in android {} block to enable the ViewBinding. After inserting these lines synchronise the gradle and you are good to go.
android {
... other blocks ...
buildFeatures {
viewBinding true
}
}
Get ready with ViewBinding
Since we have enabled ViewBinding, therefore we don’t have to use findViewById() anymore. First we have to get the binding object and that binding object will provide the element reference id from layout file. To do this we have to know the binding class name. The class is autogenerated and it is named using the layout file name. Since our layout file name is activity_main.xml so, the binding class name will be ActivityMainBinding.
Benefit of using ViewBinding is that all layout elements with id will be available as binding property. The binding class will have root property to denote the root layout or the parent layout. This root should be passed into the setContentView() to render the layout file using the ViewBinding.
Note: Double check to see if you are using setContentView(binding.root) instead of setContentView(R.layout.activity_main). Else the listeners and data set using binding properties will not reflect.
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
}
Display Progress in ProgressBar
To display progress in a ProgressBar we have to set the progress property of the ProgressBar.
val progress = binding.pbDetails.progress + 10
binding.pbDetails.progress = progress
We will update the TextView and the ProgressBar with the new progress by getting the previous progress from the ProgressBar and adding 10 to it. Ideally if we get percentage we should set the value directly to the ProgressBar’s progress. But to demonstrate the progressing view we are adding 10 to the previous progress.
private fun showProgress() {
handler.postDelayed({
val progress = binding.pbDetails.progress + 10
binding.tvProgress.text = "$progress/100..."
binding.pbDetails.progress = progress
if (progress < 100) {
showProgress()
} else {
binding.tvProgress.text = "Download/Initialization Completed"
binding.pbDetails.visibility = View.GONE
}
}, 900)
}
Complete MainActivity.kt
Here is the complete MainActivity.kt with all the imports used in the class.
package com.pcsalt.example.progressdemo
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import com.pcsalt.example.progressdemo.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private var handler = Handler(Looper.getMainLooper())
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.tvProgress.text = "0/100..."
showProgress()
}
private fun showProgress() {
handler.postDelayed({
val progress = binding.pbDetails.progress + 10
binding.tvProgress.text = "$progress/100..."
binding.pbDetails.progress = progress
if (progress < 100) {
showProgress()
} else {
binding.tvProgress.text = "Download/Initialization Completed"
binding.pbDetails.visibility = View.GONE
}
}, 900)
}
}
Screenshots
Following are the screenshots of the application.
Points to remember
- ProgressBar displays progress if and only if style is set to Horizontal i.e.
style="@style/Widget.AppCompat.ProgressBar.Horizontal"
max
property should be set either using XML’s propertyandroid:max="<value>"
or using ProgressBar class’s instance methodProgressBar#setMax(int)
- Default value of max is 100 and progress percentage will be calculated.
- Double check to see if you are using setContentView(binding.root) instead of setContentView(R.layout.activity_main). Else the listeners and data set using binding properties will not reflect.
Video Tutorial on YouTube
Download Source Code
The complete source code is pushed to GitHub repo. Browse it by clicking the octocat icon.