Tuesday, June 2, 2020

android kotlin - Horizontal ProgressBar programmatically

MainActivity.kt

package com.example.jetpack

import android.content.Context
import android.os.Bundle
import android.os.Handler
import android.util.TypedValue
import android.view.View
import android.widget.ProgressBar
import androidx.appcompat.app.AppCompatActivity
import androidx.constraintlayout.widget.ConstraintSet
import kotlinx.android.synthetic.main.activity_main.*
import kotlin.random.Random
import androidx.constraintlayout.widget.ConstraintLayout.LayoutParams


class MainActivity : AppCompatActivity() {
    var progressStatus = 0
    var handler = Handler()

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

        // create a horizontal progress bar programmatically
        val progressBar = ProgressBar(
            this,
            null,
            android.R.attr.progressBarStyleHorizontal
        )
        // generate a view id for the progress bar
        progressBar.id = View.generateViewId()

        // progress bar width and height
        val params = LayoutParams(
            LayoutParams.MATCH_PARENT,
            LayoutParams.WRAP_CONTENT
        )
        progressBar.layoutParams = params

        // add the progress bar to constraint layout
        constraintLayout.addView(progressBar)

        // initialize a new constraint set
        val constraintSet = ConstraintSet()
        constraintSet.clone(constraintLayout)

        // put the progress bar bottom of text view
        constraintSet.connect(
            // connect progress bar top to text view's bottom
            progressBar.id,
            ConstraintSet.TOP,
            R.id.textView,
            ConstraintSet.BOTTOM,
            24.toDp(this) // margin
        )

        // start constraint with margin
        constraintSet.connect(
            progressBar.id,
            ConstraintSet.START,
            R.id.constraintLayout,
            ConstraintSet.START,
            16.toDp(this) // margin
        )

        // end constraint with margin
        constraintSet.connect(
            progressBar.id,
            ConstraintSet.END,
            R.id.constraintLayout,
            ConstraintSet.END,
            16.toDp(this)
        )

        // finally, apply the constraint to constraint layout
        constraintSet.applyTo(constraintLayout)


        button.setOnClickListener {
            button.isEnabled = false

            // set up progress bar on initial stage
            progressBar.progress = 0
            progressStatus = 0

            // generate random number of files to download
            val filesToDownload= Random.nextInt(10,200)

            // set up max value for progress bar
            progressBar.max = filesToDownload

            Thread(Runnable {
                while (progressStatus < filesToDownload){
                    // update progress status
                    progressStatus +=1

                    // sleep the thread for 50 milliseconds
                    Thread.sleep(50)

                    // update the progress bar
                    handler.post {
                        progressBar.progress = progressStatus

                        // calculate the percentage
                        var percentage = ((progressStatus.toDouble()
                                / filesToDownload) * 100).toInt()

                        // update the text view
                        textView.text = "Downloaded $progressStatus of " +
                                "$filesToDownload files ($percentage%)"

                        if (progressStatus == filesToDownload){
                            button.isEnabled = true
                        }
                    }
                }
            }).start()
        }
    }
}


// Extension method to convert pixels to dp
fun Int.toDp(context: Context):Int = TypedValue.applyDimension(
    TypedValue.COMPLEX_UNIT_DIP,this.toFloat(),context.resources.displayMetrics
).toInt()
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"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/constraintLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <com.google.android.material.textview.MaterialTextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginTop="8dp"
        android:padding="24dp"
        android:text="0"
        android:textAppearance="@style/TextAppearance.MaterialComponents.Headline6"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.51"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/button" />

    <com.google.android.material.button.MaterialButton
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="8dp"
        android:text="Start Task"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.538"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>